Ticket #8692: wagFileParsing.patch

File wagFileParsing.patch, 21.6 KB (added by SF/buddha_, 17 years ago)

WAG file parsing patch to the AGI's fallback detector

  • engines/agi/detection.cpp

     
    18261826};
    18271827
    18281828/**
     1829 * WagProperty represents a single property from WinAGI's *.wag file.
     1830 * A property consists of a header and of data.
     1831 * The header consists of the following:
     1832 * - Property code (Integer/Enumeration, 1 byte)
     1833 * - Property type (Integer/Enumeration, 1 byte)
     1834 * - Property number (Integer, 1 byte)
     1835 * - Property size (Little endian integer, 2 bytes)
     1836 * And then there's the data with as many bytes as defined in the header's property size variable.
     1837 */
     1838class WagProperty {
     1839// Constants, enumerations etc
     1840public:
     1841        /**
     1842         * Property codes taken from WinAGI 1.1.21's source code file WinAGI/AGIObjects.bas.
     1843         */
     1844        enum WagPropertyCode {
     1845                PC_GAMEDESC = 129, ///< Game description (WinAGI 1.1.21 limits these to 4096 bytes)
     1846                PC_GAMEAUTHOR,     ///< Game author (WinAGI 1.1.21 limits these to 256 bytes)
     1847                PC_GAMEID,         ///< Game ID
     1848                PC_INTVERSION,     ///< Interpreter version (WinAGI 1.1.21 defaults to version 2.917)
     1849                PC_GAMELAST,       ///< Last edit date
     1850                PC_GAMEVERSION,    ///< Game version (WinAGI 1.1.21 limits these to 256 bytes)
     1851                PC_GAMEABOUT,      ///< About game (WinAGI 1.1.21 limits these to 4096 bytes)
     1852                PC_GAMEEXEC,       ///< Game executable
     1853                PC_RESDIR,         ///< Resource directory name
     1854                PC_DEFSYNTAX,      ///< Default syntax
     1855                PC_INVOBJDESC = 144,
     1856                PC_VOCABWORDDESC = 160,
     1857                PC_PALETTE = 172,
     1858                PC_USERESNAMES = 180,
     1859                PC_LOGIC = 192,
     1860                PC_PICTURE = 208,
     1861                PC_SOUND = 224,
     1862                PC_VIEW = 240,
     1863                PC_UNDEFINED = 0x100 ///< An undefined property code (Added for ScummVM).
     1864        };
     1865       
     1866        /**
     1867         * Property types taken from WinAGI 1.1.21's source code file WinAGI/AGIObjects.bas.
     1868         * At the moment these aren't really at all needed by ScummVM. Just here if anyone decides to use them.
     1869         */
     1870        enum WagPropertyType {
     1871                PT_ID,
     1872                PT_DESC,
     1873                PT_SYNTAX,
     1874                PT_CRC32,
     1875                PT_KEY,
     1876                PT_INST0,
     1877                PT_INST1,
     1878                PT_INST2,
     1879                PT_MUTE0,
     1880                PT_MUTE1,
     1881                PT_MUTE2,
     1882                PT_MUTE3,
     1883                PT_TPQN,
     1884                PT_ROOM,
     1885                PT_VIS0,
     1886                PT_VIS1,
     1887                PT_VIS2,
     1888                PT_VIS3,
     1889                PT_ALL = 0xff,
     1890                PT_UNDEFINED = 0x100 ///< An undefined property type (Added for ScummVM).
     1891        };
     1892
     1893// Constructors, destructors, operators etc
     1894public:
     1895        /**
     1896         * Creates an empty WagProperty object.
     1897         * No property header or property data in it.
     1898         */
     1899        WagProperty();
     1900       
     1901        /**
     1902         * Destructor. Releases allocated memory if any etc. The usual.
     1903         */
     1904        ~WagProperty();
     1905
     1906        /**
     1907         * Copy constructor. Deep copies the variables.
     1908         */
     1909        WagProperty(const WagProperty &other);
     1910
     1911        /**
     1912         * Assignment operator. Deep copies the variables.
     1913         */
     1914        WagProperty &operator=(const WagProperty &other);
     1915
     1916// Non-public helper methods
     1917protected:
     1918        /**
     1919         * Sets the default values for member variables.
     1920         */
     1921        void setDefaults();
     1922       
     1923        /**
     1924         * Delete's the property's data from memory if we have it, otherwise does nothing.
     1925         */
     1926        void deleteData();
     1927
     1928        /**
     1929         * Deep copies the parameter object to this object.
     1930         * @param other The object to be deep copied to this object.
     1931         */
     1932        void deepCopy(const WagProperty &other);
     1933
     1934// Public methods that have side-effects
     1935public:
     1936        /**
     1937         * Read in a property (Header and data).
     1938         * @return True if reading was a success, false otherwise.
     1939         */
     1940        bool read(Common::SeekableReadStream &stream);
     1941       
     1942        /**
     1943         * Clears the property.
     1944         * After this the property is empty. No header or data.
     1945         */
     1946        void clear();
     1947
     1948// Public access functions
     1949public:
     1950        /**
     1951         * Was the property read ok from the source stream?
     1952         */
     1953        bool readOk() const { return _readOk; };
     1954
     1955        /**
     1956         * Return the property's code.
     1957         * @return The property's code if readOk(), PC_UNDEFINED otherwise.
     1958         */
     1959        enum WagPropertyCode getCode() const { return _propCode; };
     1960       
     1961        /**
     1962         * Return the property's type.
     1963         * @return The property's type if readOk(), PT_UNDEFINED otherwise.
     1964         */     
     1965        enum WagPropertyType getType() const { return _propType; };
     1966       
     1967        /**
     1968         * Return the property's number.
     1969         * @return The property's number if readOk(), 0 otherwise.
     1970         */     
     1971        byte getNumber() const { return _propNum; };
     1972       
     1973        /**
     1974         * Return the property's data's length.
     1975         * @return The property's data's length if readOk(), 0 otherwise.
     1976         */
     1977        uint16 getSize() const { return _propSize; }
     1978       
     1979        /**
     1980         * Return property's data. Constant access version.
     1981         * Can be used as a C-style string (i.e. this is guaranteed to have a trailing zero).
     1982         * @return The property's data if readOk(), NULL otherwise.
     1983         */
     1984        const char *getData() const { return _propData; };
     1985
     1986// Member variables
     1987protected:
     1988        bool _readOk;                   ///< Was the property read ok from the source stream?
     1989        enum WagPropertyCode _propCode; ///< Property code (Part of the property's header)
     1990        enum WagPropertyType _propType; ///< Property type (Part of the property's header)
     1991        byte _propNum;                  ///< Property number (Part of the property's header)
     1992        uint16 _propSize;               ///< Property's size (Part of the property's header)
     1993        char *_propData;                ///< The property's data (Plus a trailing zero for C-style string access)
     1994};
     1995
     1996WagProperty::WagProperty() {
     1997        setDefaults();
     1998}
     1999
     2000WagProperty::~WagProperty() {
     2001        deleteData();
     2002}
     2003
     2004WagProperty::WagProperty(const WagProperty &other) {
     2005        deepCopy(other);
     2006}
     2007
     2008WagProperty &WagProperty::operator=(const WagProperty &other) {
     2009        if (&other != this) deepCopy(other); // Don't do self-assignment
     2010        return *this;
     2011}
     2012
     2013void WagProperty::deepCopy(const WagProperty &other) {
     2014        _readOk   = other._readOk;
     2015        _propCode = other._propCode;
     2016        _propType = other._propType;
     2017        _propNum  = other._propNum;
     2018        _propSize = other._propSize;
     2019
     2020        deleteData(); // Delete old data (If any) and set _propData to NULL
     2021        if (other._propData != NULL) {
     2022                _propData = new char[other._propSize + 1UL]; // Allocate space for property's data plus trailing zero
     2023                memcpy(_propData, other._propData, other._propSize + 1UL); // Copy the whole thing
     2024        }
     2025}
     2026
     2027bool WagProperty::read(Common::SeekableReadStream &stream) {
     2028        // First read the property's header
     2029        _propCode = (enum WagPropertyCode) stream.readByte();
     2030        _propType = (enum WagPropertyType) stream.readByte();
     2031        _propNum  = stream.readByte();
     2032        _propSize = stream.readUint16LE();
     2033
     2034        if (stream.ioFailed()) { // Check that we got the whole header
     2035                _readOk = false;
     2036                return _readOk;
     2037        }
     2038
     2039        // Then read the property's data
     2040        deleteData(); // Delete old data (If any)
     2041        _propData = new char[_propSize + 1UL]; // Allocate space for property's data plus trailing zero
     2042        uint32 readBytes = stream.read(_propData, _propSize); // Read the data in
     2043        _propData[_propSize] = 0; // Set the trailing zero for easy C-style string access
     2044
     2045        _readOk = (_propData != NULL && readBytes == _propSize); // Check that we got the whole data
     2046        return _readOk;
     2047}
     2048
     2049void WagProperty::clear() {
     2050        deleteData();
     2051        setDefaults();
     2052}
     2053
     2054void WagProperty::setDefaults() {       
     2055        _readOk   = false;
     2056        _propCode = PC_UNDEFINED;
     2057        _propType = PT_UNDEFINED;
     2058        _propNum  = 0;
     2059        _propSize = 0;
     2060        _propData = NULL;
     2061}
     2062
     2063void WagProperty::deleteData() {
     2064        if (_propData != NULL) {
     2065                delete _propData;
     2066                _propData = NULL;
     2067        }
     2068}
     2069
     2070/**
     2071 * Class for parsing *.wag files created by WinAGI.
     2072 * Using this class you can get information about fanmade AGI games if they have provided a *.wag file with them.
     2073 */
     2074class WagFileParser {
     2075// Constants, type definitions, enumerations etc.
     2076public:
     2077        static const int WINAGI_VERSION_LENGTH = 16; ///< WinAGI's version string's length (Always 16) 
     2078        typedef Common::Array<WagProperty> PropertyList; ///< A type definition for an array of *.wag file properties
     2079       
     2080public:
     2081        /**
     2082         * Constructor. Creates a WagFileParser object in a default state.
     2083         */
     2084        WagFileParser();
     2085       
     2086        /**
     2087         * Destructor.
     2088         */
     2089        ~WagFileParser();
     2090
     2091        /**
     2092         * Loads a *.wag file and parses it.
     2093         * @note After this you can access the loaded properties using getProperty() and getProperties() etc.
     2094         * @param filename Name of the file to be parsed.
     2095         * @return True if parsed successfully, false otherwise.
     2096         */     
     2097        bool parse(const char *filename);
     2098
     2099        /**
     2100         * Get list of the loaded properties.
     2101         * @note Use only after a call to parse() first.
     2102         * @return The list of loaded properties.
     2103         */
     2104        const PropertyList &getProperties() const { return _propList; };
     2105       
     2106        /**
     2107         * Get property with the given property code.
     2108         * @note Use only after a call to parse() first.
     2109         * @return Pointer to the property if its found in memory, NULL otherwise.
     2110         *
     2111         * TODO/FIXME: Handle cases where several properties with the given property code are found.
     2112         *             At the moment we don't need this functionality because the properties we use
     2113         *             for fallback detection probably don't have multiples in the WAG-file.
     2114         * TODO: Make this faster than linear time if desired/needed.
     2115         */
     2116        const WagProperty *getProperty(const WagProperty::WagPropertyCode code) const;
     2117
     2118        /**
     2119         * Tests if the given property contains a valid AGI interpreter version string.
     2120         * A valid AGI interpreter version string is of the form "X.Y" or "X,Y" where
     2121         * X is a single decimal digit and Y is a string of decimal digits (At least one digit).
     2122         * @param version The property to be tested.
     2123         * @return True if the given property contains a valid AGI interpreter version string, false otherwise.
     2124         */
     2125        bool checkAgiVersionProperty(const WagProperty &version) const;
     2126
     2127        /**
     2128         * Convert property's data to an AGI interpreter version number.
     2129         * @param version The property to be converted (Property code should be PC_INTVERSION).
     2130         * @return AGI interpreter version number if successful, 0 otherwise.
     2131         */
     2132        uint16 convertToAgiVersionNumber(const WagProperty &version);
     2133       
     2134        /**
     2135         * Was the file parsed successfully?
     2136         * @return True if file was parsed successfully, false otherwise.
     2137         */
     2138        bool parsedOk() const { return _parsedOk; };
     2139
     2140protected:
     2141        /**
     2142         * Checks if stream has a valid WinAGI version string in its end.
     2143         * @param stream The stream to be checked.
     2144         * @return True if reading was successful and stream contains a valid WinAGI version string, false otherwise.
     2145         */
     2146        bool checkWagVersion(Common::SeekableReadStream &stream);
     2147
     2148        /**
     2149         * Checks if we're at or past the end of the properties stored in the stream.
     2150         * @param stream The stream whose seeking position is to be checked.
     2151         * @return True if stream's seeking position is at or past the end of the properties, false otherwise.
     2152         */
     2153        bool endOfProperties(const Common::SeekableReadStream &stream) const;
     2154
     2155// Member variables
     2156protected:
     2157        PropertyList _propList; ///< List of loaded properties from the file.
     2158        bool         _parsedOk; ///< Did the parsing of the file go ok?
     2159};
     2160
     2161WagFileParser::WagFileParser() :
     2162        _parsedOk(false) {
     2163}
     2164
     2165WagFileParser::~WagFileParser() {
     2166}
     2167
     2168bool WagFileParser::checkAgiVersionProperty(const WagProperty &version) const {
     2169        if (version.getCode() == WagProperty::PC_INTVERSION && // Must be AGI interpreter version property
     2170                version.getSize() >= 3 && // Need at least three characters for a version number like "X.Y"
     2171                isdigit(version.getData()[0]) && // And the first character must be a digit
     2172                (version.getData()[1] == ',' || version.getData()[1] == '.')) { // And the second a comma or a period
     2173
     2174                for (int i = 2; i < version.getSize(); i++) // And the rest must all be digits
     2175                        if (!isdigit(version.getData()[i]))
     2176                                return false; // Bail out if found a non-digit after the decimal point
     2177
     2178                return true;
     2179        } else // Didn't pass the preliminary test so fails
     2180                return false;
     2181}
     2182
     2183uint16 WagFileParser::convertToAgiVersionNumber(const WagProperty &version) {
     2184        // Examples of the conversion: "2.44" -> 0x2440, "2.917" -> 0x2917, "3.002086" -> 0x3086.
     2185        if (checkAgiVersionProperty(version)) { // Check that the string is a valid AGI interpreter version string
     2186                // Convert first ascii digit to an integer and put it in the fourth nibble (Bits 12...15) of the version number
     2187                // and at the same time set all other nibbles to zero.
     2188                uint16 agiVerNum = ((uint16) (version.getData()[0] - '0')) << (3 * 4);
     2189               
     2190                // Convert at most three least significant digits of the version number's minor part
     2191                // (i.e. the part after the decimal point) and put them in order to the third, second
     2192                // and the first nibble of the version number. Just to clarify version.getSize() - 2
     2193                // is the number of digits after the decimal point.
     2194                int32 digitCount = MIN<int32>(3, ((int32) version.getSize()) - 2); // How many digits left to convert
     2195                for (int i = 0; i < digitCount; i++)
     2196                        agiVerNum |= ((uint16) (version.getData()[version.getSize() - digitCount + i] - '0')) << ((2 - i) * 4);
     2197
     2198                debug(3, "WagFileParser: Converted AGI version from string %s to number 0x%x", version.getData(), agiVerNum);
     2199                return agiVerNum;
     2200        } else // Not a valid AGI interpreter version string
     2201                return 0; // Can't convert, so failure
     2202}
     2203
     2204bool WagFileParser::checkWagVersion(Common::SeekableReadStream &stream) {
     2205        if (stream.size() >= WINAGI_VERSION_LENGTH) { // Stream has space to contain the WinAGI version string
     2206                // Read the last WINAGI_VERSION_LENGTH bytes of the stream and make a string out of it
     2207                char str[WINAGI_VERSION_LENGTH+1]; // Allocate space for the trailing zero also
     2208                uint32 oldStreamPos = stream.pos(); // Save the old stream position
     2209                stream.seek(stream.size() - WINAGI_VERSION_LENGTH);
     2210                uint32 readBytes = stream.read(str, WINAGI_VERSION_LENGTH);
     2211                stream.seek(oldStreamPos); // Seek back to the old stream position
     2212                str[readBytes] = 0; // Set the trailing zero to finish the C-style string
     2213                if (readBytes != WINAGI_VERSION_LENGTH) { // Check that we got the whole version string
     2214                        debug(3, "WagFileParser::checkWagVersion: Error reading WAG file version from stream");
     2215                        return false;
     2216                }
     2217                debug(3, "WagFileParser::checkWagVersion: Read WinAGI version string (\"%s\")", str);
     2218
     2219                // Check that the WinAGI version string is one of the two version strings
     2220                // WinAGI 1.1.21 recognizes as acceptable in the end of a *.wag file.
     2221                // Note that they are all of length 16 and are padded with spaces to be that long.
     2222                return scumm_stricmp(str, "WINAGI v1.0     ") == 0 ||
     2223                        scumm_stricmp(str, "1.0 BETA        ") == 0;
     2224        } else { // Stream is too small to contain the WinAGI version string
     2225                debug(3, "WagFileParser::checkWagVersion: Stream is too small to contain a valid WAG file");
     2226                return false;
     2227        }
     2228}
     2229
     2230bool WagFileParser::parse(const char *filename) {
     2231        Common::File file;
     2232        WagProperty property; // Temporary property used for reading
     2233        Common::MemoryReadStream *stream = NULL; // The file is to be read fully into memory and handled using this
     2234
     2235        _parsedOk = false; // We haven't parsed the file yet
     2236
     2237        if (file.open(filename)) { // Open the file
     2238                stream = file.readStream(file.size()); // Read the file into memory
     2239                if (stream != NULL && stream->size() == file.size()) { // Check that the whole file was read into memory
     2240                        if (checkWagVersion(*stream)) { // Check that WinAGI version string is valid
     2241                                // It seems we've got a valid *.wag file so let's parse its properties from the start.
     2242                                stream->seek(0); // Rewind the stream
     2243                                if (!_propList.empty()) _propList.clear(); // Clear out old properties (If any)
     2244                               
     2245                                do { // Parse the properties
     2246                                        if (property.read(*stream)) { // Read the property and check it was read ok
     2247                                                _propList.push_back(property); // Add read property to properties list
     2248                                                debug(4, "WagFileParser::parse: Read property with code %d, type %d, number %d, size %d, data \"%s\"",
     2249                                                        property.getCode(), property.getType(), property.getNumber(), property.getSize(), property.getData());
     2250                                        } else // Reading failed, let's bail out
     2251                                                break;
     2252                                } while (!endOfProperties(*stream)); // Loop until the end of properties
     2253
     2254                                // File was parsed successfully only if we got to the end of properties
     2255                                // and all the properties were read successfully (Also the last).
     2256                                _parsedOk = endOfProperties(*stream) && property.readOk();
     2257
     2258                                if (!_parsedOk) // Error parsing stream
     2259                                        warning("Error parsing WAG file (%s). WAG file ignored", filename);
     2260                        } else // Invalid WinAGI version string or it couldn't be read
     2261                                warning("Invalid WAG file (%s) version or error reading it. WAG file ignored", filename);
     2262                } else // Couldn't fully read file into memory
     2263                        warning("Error reading WAG file (%s) into memory. WAG file ignored", filename);
     2264        } else // Couldn't open file
     2265                warning("Couldn't open WAG file (%s). WAG file ignored", filename);
     2266
     2267        if (stream != NULL) delete stream; // If file was read into memory, deallocate that buffer
     2268        return _parsedOk;
     2269}
     2270
     2271const WagProperty *WagFileParser::getProperty(const WagProperty::WagPropertyCode code) const {
     2272        for (PropertyList::const_iterator iter = _propList.begin(); iter != _propList.end(); iter++)
     2273                if (iter->getCode() == code) return iter;
     2274        return NULL;
     2275}
     2276
     2277bool WagFileParser::endOfProperties(const Common::SeekableReadStream &stream) const {
     2278        return stream.pos() >= (stream.size() - WINAGI_VERSION_LENGTH);
     2279}
     2280
     2281/**
    18292282 * The fallback game descriptor used by the AGI engine's fallbackDetector.
    18302283 * Contents of this struct are to be overwritten by the fallbackDetector.
    18312284 */
     
    18482301        typedef Common::HashMap<Common::String, int32, Common::CaseSensitiveString_Hash, Common::CaseSensitiveString_EqualTo> IntMap;
    18492302        IntMap allFiles;
    18502303        bool matchedUsingFilenames = false;
     2304        bool matchedUsingWag = false;
     2305        int wagFileCount = 0;
     2306        WagFileParser wagFileParser;
     2307        Common::String wagFilePath;
    18512308        Common::String gameid("agi-fanmade"), description, extra; // Set the defaults for gameid, description and extra
    18522309        FSList fslistCurrentDir; // Only used if fslist == NULL
    18532310
     
    18682325        g_fallbackDesc.features = GF_FANMADE;
    18692326        g_fallbackDesc.version = 0x2917;
    18702327
    1871         // First grab all filenames
     2328        // First grab all filenames and at the same time count the number of *.wag files
    18722329        for (FSList::const_iterator file = fslist->begin(); file != fslist->end(); ++file) {
    18732330                if (file->isDirectory()) continue;
    18742331                Common::String filename = file->name();
    18752332                filename.toLowercase();
    18762333                allFiles[filename] = true; // Save the filename in a hash table
     2334               
     2335                if (filename.hasSuffix(".wag")) {
     2336                        // Save latest found *.wag file's path (Can be used to open the file, the name can't)
     2337                        wagFilePath = file->path();
     2338                        wagFileCount++; // Count found *.wag files
     2339                }
    18772340        }
    18782341
    18792342        if (allFiles.contains("logdir") && allFiles.contains("object") &&
     
    19092372                        }
    19102373                }
    19112374        }
    1912        
     2375
     2376        // WinAGI produces *.wag file with interpreter version, game name and other parameters.
     2377        // If there's exactly one *.wag file and it parses successfully then we'll use its information.
     2378        if (wagFileCount == 1 && wagFileParser.parse(wagFilePath.c_str())) {
     2379                matchedUsingWag = true;
     2380
     2381                const WagProperty *wagAgiVer = wagFileParser.getProperty(WagProperty::PC_INTVERSION);
     2382                const WagProperty *wagGameID = wagFileParser.getProperty(WagProperty::PC_GAMEID);
     2383                const WagProperty *wagGameDesc = wagFileParser.getProperty(WagProperty::PC_GAMEDESC);
     2384                const WagProperty *wagGameVer = wagFileParser.getProperty(WagProperty::PC_GAMEVERSION);
     2385                const WagProperty *wagGameLastEdit = wagFileParser.getProperty(WagProperty::PC_GAMELAST);
     2386
     2387                // If there is an AGI version number in the *.wag file then let's use it
     2388                if (wagAgiVer != NULL && wagFileParser.checkAgiVersionProperty(*wagAgiVer)) {
     2389                        // TODO/FIXME: Check that version number is something we support before trying to use it.
     2390                        //     If the version number is unsupported then it'll get switched to 0x2917 later.
     2391                        //     But there's the possibility that file based detection has detected something else
     2392                        //     than a v2 AGI game. So there's a possibility for conflicting information.
     2393                        g_fallbackDesc.version = wagFileParser.convertToAgiVersionNumber(*wagAgiVer);
     2394                }
     2395
     2396                // Set gameid according to *.wag file information if it's present and it doesn't contain whitespace.
     2397                if (wagGameID != NULL && !Common::String(wagGameID->getData()).contains(" ")) {
     2398                        gameid = wagGameID->getData();
     2399                        debug(3, "Agi::fallbackDetector: Using game id (%s) from WAG file", gameid.c_str());
     2400                }
     2401
     2402                // Set game description and extra according to *.wag file information if they're present
     2403                if (wagGameDesc != NULL) {
     2404                        description = wagGameDesc->getData();
     2405                        debug(3, "Agi::fallbackDetector: Game description (%s) from WAG file", wagGameDesc->getData());
     2406
     2407                        // If there's game version in the *.wag file, set extra to it
     2408                        if (wagGameVer != NULL) {
     2409                                extra = wagGameVer->getData();
     2410                                debug(3, "Agi::fallbackDetector: Game version (%s) from WAG file", wagGameVer->getData());
     2411                        }
     2412
     2413                        // If there's game last edit date in the *.wag file, add it to extra
     2414                        if (wagGameLastEdit != NULL) {
     2415                                if (!extra.empty() ) extra += " ";
     2416                                extra += wagGameLastEdit->getData();
     2417                                debug(3, "Agi::fallbackDetector: Game's last edit date (%s) from WAG file", wagGameLastEdit->getData());
     2418                        }
     2419                }
     2420        } else if (wagFileCount > 1) { // More than one *.wag file, confusing! So let's not use them.
     2421                warning("More than one (%d) *.wag files found. WAG files ignored", wagFileCount);
     2422        }
     2423
    19132424        // Check that the AGI interpreter version is a supported one
    19142425        if (!(g_fallbackDesc.version >= 0x2000 && g_fallbackDesc.version < 0x4000)) {
    19152426                warning("Unsupported AGI interpreter version 0x%x in AGI's fallback detection. Using default 0x2917", g_fallbackDesc.version);
     
    19242435
    19252436        // Check if we found a match with any of the fallback methods
    19262437        Common::EncapsulatedADGameDesc result;
    1927         if (matchedUsingFilenames) {
     2438        if (matchedUsingWag || matchedUsingFilenames) {
    19282439                extra = description + " " + extra; // Let's combine the description and extra
    19292440                result = Common::EncapsulatedADGameDesc((const Common::ADGameDescription *)&g_fallbackDesc, gameid, extra);
    19302441