Example #1
0
const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
	bool foundResMap = false;
	bool foundRes000 = false;

	// Set some defaults
	s_fallbackDesc.extra = "";
	s_fallbackDesc.language = Common::EN_ANY;
	s_fallbackDesc.flags = ADGF_NO_FLAGS;
	s_fallbackDesc.platform = Common::kPlatformPC;	// default to PC platform
	s_fallbackDesc.gameid = "sci";
	s_fallbackDesc.guioptions = GUIO0();

	if (allFiles.contains("resource.map") || allFiles.contains("Data1")
	    || allFiles.contains("resmap.001") || allFiles.contains("resmap.001")) {
		foundResMap = true;
	}

	// Determine if we got a CD version and set the CD flag accordingly, by checking for
	// resource.aud for SCI1.1 CD games, or audio001.002 for SCI1 CD games. We assume that
	// the file should be over 10MB, as it contains all the game speech and is usually
	// around 450MB+. The size check is for some floppy game versions like KQ6 floppy, which
	// also have a small resource.aud file
	if (allFiles.contains("resource.aud") || allFiles.contains("audio001.002")) {
		Common::FSNode file = allFiles.contains("resource.aud") ? allFiles["resource.aud"] :  allFiles["audio001.002"];
		Common::SeekableReadStream *tmpStream = file.createReadStream();
		if (tmpStream->size() > 10 * 1024 * 1024) {
			// We got a CD version, so set the CD flag accordingly
			s_fallbackDesc.flags |= ADGF_CD;
		}
		delete tmpStream;
	}

	if (allFiles.contains("resource.000") || allFiles.contains("resource.001")
		|| allFiles.contains("ressci.000") || allFiles.contains("ressci.001"))
		foundRes000 = true;

	// Data1 contains both map and volume for SCI1.1+ Mac games
	if (allFiles.contains("Data1")) {
		foundResMap = foundRes000 = true;
		 s_fallbackDesc.platform = Common::kPlatformMacintosh;
	}

	// Determine the game platform
	// The existence of any of these files indicates an Amiga game
	if (allFiles.contains("9.pat") || allFiles.contains("spal") ||
		allFiles.contains("patch.005") || allFiles.contains("bank.001"))
			s_fallbackDesc.platform = Common::kPlatformAmiga;

	// The existence of 7.pat or patch.200 indicates a Mac game
	if (allFiles.contains("7.pat") || allFiles.contains("patch.200"))
		s_fallbackDesc.platform = Common::kPlatformMacintosh;

	// The data files for Atari ST versions are the same as their DOS counterparts


	// If these files aren't found, it can't be SCI
	if (!foundResMap && !foundRes000) {
		return 0;
	}

	ResourceManager resMan;
	resMan.addAppropriateSources(fslist);
	resMan.init(true);
	// TODO: Add error handling.

#ifndef ENABLE_SCI32
	// Is SCI32 compiled in? If not, and this is a SCI32 game,
	// stop here
	if (getSciVersion() >= SCI_VERSION_2) {
		return (const ADGameDescription *)&s_fallbackDesc;
	}
#endif

	ViewType gameViews = resMan.getViewType();

	// Have we identified the game views? If not, stop here
	// Can't be SCI (or unsupported SCI views). Pinball Creep by sierra also uses resource.map/resource.000 files
	//  but doesnt share sci format at all, if we dont return 0 here we will detect this game as SCI
	if (gameViews == kViewUnknown) {
		return 0;
	}

	// Set the platform to Amiga if the game is using Amiga views
	if (gameViews == kViewAmiga)
		s_fallbackDesc.platform = Common::kPlatformAmiga;

	// Determine the game id
	Common::String sierraGameId = resMan.findSierraGameId();

	// If we don't have a game id, the game is not SCI
	if (sierraGameId.empty()) {
		return 0;
	}

	Common::String gameId = convertSierraGameId(sierraGameId, &s_fallbackDesc.flags, resMan);
	strncpy(s_fallbackGameIdBuf, gameId.c_str(), sizeof(s_fallbackGameIdBuf) - 1);
	s_fallbackGameIdBuf[sizeof(s_fallbackGameIdBuf) - 1] = 0;	// Make sure string is NULL terminated
	s_fallbackDesc.gameid = s_fallbackGameIdBuf;

	// Try to determine the game language
	// Load up text 0 and start looking for "#" characters
	// Non-English versions contain strings like XXXX#YZZZZ
	// Where XXXX is the English string, #Y a separator indicating the language
	// (e.g. #G for German) and ZZZZ is the translated text
	// NOTE: This doesn't work for games which use message instead of text resources
	// (like, for example, Eco Quest 1 and all SCI1.1 games and newer, e.g. Freddy Pharkas).
	// As far as we know, these games store the messages of each language in separate
	// resources, and it's not possible to detect that easily
	// Also look for "%J" which is used in japanese games
	Resource *text = resMan.findResource(ResourceId(kResourceTypeText, 0), 0);
	uint seeker = 0;
	if (text) {
		while (seeker < text->size) {
			if (text->data[seeker] == '#')  {
				if (seeker + 1 < text->size)
					s_fallbackDesc.language = charToScummVMLanguage(text->data[seeker + 1]);
				break;
			}
			if (text->data[seeker] == '%') {
				if ((seeker + 1 < text->size) && (text->data[seeker + 1] == 'J')) {
					s_fallbackDesc.language = charToScummVMLanguage(text->data[seeker + 1]);
					break;
				}
			}
			seeker++;
		}
	}


	// Fill in "extra" field

	// Is this an EGA version that might have a VGA pendant? Then we want
	// to mark it as such in the "extra" field.
	const bool markAsEGA = (gameViews == kViewEga && s_fallbackDesc.platform != Common::kPlatformAmiga
			&& getSciVersion() > SCI_VERSION_1_EGA_ONLY);

	const bool isDemo = (s_fallbackDesc.flags & ADGF_DEMO);
	const bool isCD = (s_fallbackDesc.flags & ADGF_CD);

	if (!isCD)
		s_fallbackDesc.guioptions = GUIO1(GUIO_NOSPEECH);

	if (gameId.hasSuffix("sci")) {
		s_fallbackDesc.extra = "SCI";

		// Differentiate EGA versions from the VGA ones, where needed
		if (markAsEGA)
			s_fallbackDesc.extra = "SCI/EGA";

		// Mark as demo.
		// Note: This overwrites the 'EGA' info, if it was previously set.
		if (isDemo)
			s_fallbackDesc.extra = "SCI/Demo";
	} else {
		if (markAsEGA)
			s_fallbackDesc.extra = "EGA";

		// Set "CD" and "Demo" as appropriate.
		// Note: This overwrites the 'EGA' info, if it was previously set.
		if (isDemo && isCD)
			s_fallbackDesc.extra = "CD Demo";
		else if (isDemo)
			s_fallbackDesc.extra = "Demo";
		else if (isCD)
			s_fallbackDesc.extra = "CD";
	}

	return &s_fallbackDesc;
}
Example #2
0
bool BaseFileManager::registerPackage(Common::FSNode file, const Common::String &filename, bool searchSignature) {
	PackageSet *pack = new PackageSet(file, filename, searchSignature);
	_packages.add(file.getName(), pack, pack->getPriority() , true);

	return STATUS_OK;
}
Example #3
0
static void reportUnknown(const Common::FSNode &path, const SizeMD5Map &filesSizeMD5) {
	// TODO: This message should be cleaned up / made more specific.
	// For example, we should specify at least which engine triggered this.
	//
	// Might also be helpful to display the full path (for when this is used
	// from the mass detector).
	Common::String report = Common::String::format(_("The game in '%s' seems to be unknown."), path.getPath().c_str()) + "\n";
	report += _("Please, report the following data to the ScummVM team along with name");
	report += "\n";
	report += _("of the game you tried to add and its version/language/etc.:");
	report += "\n";

	for (SizeMD5Map::const_iterator file = filesSizeMD5.begin(); file != filesSizeMD5.end(); ++file)
		report += Common::String::format("  {\"%s\", 0, \"%s\", %d},\n", file->_key.c_str(), file->_value.md5.c_str(), file->_value.size);

	report += "\n";

	g_system->logMessage(LogMessageType::kInfo, report.c_str());
}
Example #4
0
ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra) const {
	SizeMD5Map filesSizeMD5;

	const ADGameFileDescription *fileDesc;
	const ADGameDescription *g;
	const byte *descPtr;

	debug(3, "Starting detection in dir '%s'", parent.getPath().c_str());

	// Check which files are included in some ADGameDescription *and* are present.
	// Compute MD5s and file sizes for these files.
	for (descPtr = _gameDescriptors; ((const ADGameDescription *)descPtr)->gameid != 0; descPtr += _descItemSize) {
		g = (const ADGameDescription *)descPtr;

		for (fileDesc = g->filesDescriptions; fileDesc->fileName; fileDesc++) {
			Common::String fname = fileDesc->fileName;
			SizeMD5 tmp;

			if (filesSizeMD5.contains(fname))
				continue;

			// FIXME/TODO: We don't handle the case that a file is listed as a regular
			// file and as one with resource fork.

			if (g->flags & ADGF_MACRESFORK) {
				Common::MacResManager macResMan;

				if (macResMan.open(parent, fname)) {
					tmp.md5 = macResMan.computeResForkMD5AsString(_md5Bytes);
					tmp.size = macResMan.getResForkDataSize();
					debug(3, "> '%s': '%s'", fname.c_str(), tmp.md5.c_str());
					filesSizeMD5[fname] = tmp;
				}
			} else {
				if (allFiles.contains(fname)) {
					debug(3, "+ %s", fname.c_str());

					Common::File testFile;

					if (testFile.open(allFiles[fname])) {
						tmp.size = (int32)testFile.size();
						tmp.md5 = Common::computeStreamMD5AsString(testFile, _md5Bytes);
					} else {
						tmp.size = -1;
					}

					debug(3, "> '%s': '%s'", fname.c_str(), tmp.md5.c_str());
					filesSizeMD5[fname] = tmp;
				}
			}
		}
	}

	ADGameDescList matched;
	int maxFilesMatched = 0;
	bool gotAnyMatchesWithAllFiles = false;

	// MD5 based matching
	uint i;
	for (i = 0, descPtr = _gameDescriptors; ((const ADGameDescription *)descPtr)->gameid != 0; descPtr += _descItemSize, ++i) {
		g = (const ADGameDescription *)descPtr;
		bool fileMissing = false;

		// Do not even bother to look at entries which do not have matching
		// language and platform (if specified).
		if ((language != Common::UNK_LANG && g->language != Common::UNK_LANG && g->language != language
			 && !(language == Common::EN_ANY && (g->flags & ADGF_ADDENGLISH))) ||
			(platform != Common::kPlatformUnknown && g->platform != Common::kPlatformUnknown && g->platform != platform)) {
			continue;
		}

		if ((_flags & kADFlagUseExtraAsHint) && !extra.empty() && g->extra != extra)
			continue;

		bool allFilesPresent = true;
		int curFilesMatched = 0;

		// Try to match all files for this game
		for (fileDesc = g->filesDescriptions; fileDesc->fileName; fileDesc++) {
			Common::String tstr = fileDesc->fileName;

			if (!filesSizeMD5.contains(tstr)) {
				fileMissing = true;
				allFilesPresent = false;
				break;
			}

			if (fileDesc->md5 != NULL && fileDesc->md5 != filesSizeMD5[tstr].md5) {
				debug(3, "MD5 Mismatch. Skipping (%s) (%s)", fileDesc->md5, filesSizeMD5[tstr].md5.c_str());
				fileMissing = true;
				break;
			}

			if (fileDesc->fileSize != -1 && fileDesc->fileSize != filesSizeMD5[tstr].size) {
				debug(3, "Size Mismatch. Skipping");
				fileMissing = true;
				break;
			}

			debug(3, "Matched file: %s", tstr.c_str());
			curFilesMatched++;
		}

		// We found at least one entry with all required files present.
		// That means that we got new variant of the game.
		//
		// Without this check we would have erroneous checksum display
		// where only located files will be enlisted.
		//
		// Potentially this could rule out variants where some particular file
		// is really missing, but the developers should better know about such
		// cases.
		if (allFilesPresent)
			gotAnyMatchesWithAllFiles = true;

		if (!fileMissing) {
			debug(2, "Found game: %s (%s %s/%s) (%d)", g->gameid, g->extra,
			 getPlatformDescription(g->platform), getLanguageDescription(g->language), i);

			if (curFilesMatched > maxFilesMatched) {
				debug(2, " ... new best match, removing all previous candidates");
				maxFilesMatched = curFilesMatched;

				matched.clear();	// Remove any prior, lower ranked matches.
				matched.push_back(g);
			} else if (curFilesMatched == maxFilesMatched) {
				matched.push_back(g);
			} else {
				debug(2, " ... skipped");
			}

		} else {
			debug(5, "Skipping game: %s (%s %s/%s) (%d)", g->gameid, g->extra,
			 getPlatformDescription(g->platform), getLanguageDescription(g->language), i);
		}
	}

	// We didn't find a match
	if (matched.empty()) {
		if (!filesSizeMD5.empty() && gotAnyMatchesWithAllFiles) {
			reportUnknown(parent, filesSizeMD5);
		}

		// Filename based fallback
	}

	return matched;
}
Example #5
0
PackageSet::PackageSet(Common::FSNode file, const Common::String &filename, bool searchSignature) {
	uint32 absoluteOffset = 0;
	_priority = 0;
	bool boundToExe = false;
	Common::SeekableReadStream *stream = file.createReadStream();
	if (!stream) {
		return;
	}
	if (searchSignature) {
		uint32 offset;
		if (!findPackageSignature(stream, &offset)) {
			delete stream;
			return;
		} else {
			stream->seek(offset, SEEK_SET);
			absoluteOffset = offset;
			boundToExe = true;
		}
	}

	TPackageHeader hdr;
	hdr.readFromStream(stream);
	if (hdr._magic1 != PACKAGE_MAGIC_1 || hdr._magic2 != PACKAGE_MAGIC_2 || hdr._packageVersion > PACKAGE_VERSION) {
		debugC(kWintermuteDebugFileAccess | kWintermuteDebugLog, "  Invalid header in package file '%s'. Ignoring.", filename.c_str());
		delete stream;
		return;
	}

	if (hdr._packageVersion != PACKAGE_VERSION) {
		debugC(kWintermuteDebugFileAccess | kWintermuteDebugLog, "  Warning: package file '%s' is outdated.", filename.c_str());
	}
	_priority = hdr._priority;
	// new in v2
	if (hdr._packageVersion == PACKAGE_VERSION) {
		uint32 dirOffset;
		dirOffset = stream->readUint32LE();
		dirOffset += absoluteOffset;
		stream->seek(dirOffset, SEEK_SET);
	}
	assert(hdr._numDirs == 1);
	for (uint32 i = 0; i < hdr._numDirs; i++) {
		BasePackage *pkg = new BasePackage();
		if (!pkg) {
			return;
		}
		pkg->_fsnode = file;

		pkg->_boundToExe = boundToExe;

		// read package info
		byte nameLength = stream->readByte();
		char *pkgName = new char[nameLength];
		stream->read(pkgName, nameLength);
		pkg->_name = pkgName;
		pkg->_cd = stream->readByte();
		pkg->_priority = hdr._priority;
		delete[] pkgName;
		pkgName = nullptr;

		if (!hdr._masterIndex) {
			pkg->_cd = 0;    // override CD to fixed disk
		}
		_packages.push_back(pkg);

		// read file entries
		uint32 numFiles = stream->readUint32LE();

		for (uint32 j = 0; j < numFiles; j++) {
			char *name;
			uint32 offset, length, compLength, flags;/*, timeDate1, timeDate2;*/

			nameLength = stream->readByte();
			name = new char[nameLength];
			stream->read(name, nameLength);

			// v2 - xor name
			if (hdr._packageVersion == PACKAGE_VERSION) {
				for (int k = 0; k < nameLength; k++) {
					((byte *)name)[k] ^= 'D';
				}
			}
			debugC(kWintermuteDebugFileAccess, "Package contains %s", name);

			Common::String upcName = name;
			upcName.toUppercase();
			delete[] name;
			name = nullptr;

			offset = stream->readUint32LE();
			offset += absoluteOffset;
			length = stream->readUint32LE();
			compLength = stream->readUint32LE();
			flags = stream->readUint32LE();

			if (hdr._packageVersion == PACKAGE_VERSION) {
				/* timeDate1 = */ stream->readUint32LE();
				/* timeDate2 = */ stream->readUint32LE();
			}
			_filesIter = _files.find(upcName);
			if (_filesIter == _files.end()) {
				BaseFileEntry *fileEntry = new BaseFileEntry();
				fileEntry->_package = pkg;
				fileEntry->_offset = offset;
				fileEntry->_length = length;
				fileEntry->_compressedLength = compLength;
				fileEntry->_flags = flags;

				_files[upcName] = Common::ArchiveMemberPtr(fileEntry);
			} else {
				// current package has higher priority than the registered
				// TODO: This cast might be a bit ugly.
				BaseFileEntry *filePtr = (BaseFileEntry *) &*(_filesIter->_value);
				if (pkg->_priority > filePtr->_package->_priority) {
					filePtr->_package = pkg;
					filePtr->_offset = offset;
					filePtr->_length = length;
					filePtr->_compressedLength = compLength;
					filePtr->_flags = flags;
				}
			}
		}
	}
	debugC(kWintermuteDebugFileAccess, "  Registered %d files in %d package(s)", _files.size(), _packages.size());

	delete stream;
}
Example #6
0
void Engine::checkCD() {
#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__SYMBIAN32__)
	// It is a known bug under Windows that games that play CD audio cause
	// ScummVM to crash if the data files are read from the same CD. Check
	// if this appears to be the case and issue a warning.

	// If we can find a compressed audio track, then it should be ok even
	// if it's running from CD.

#ifdef USE_VORBIS
	if (Common::File::exists("track1.ogg") ||
	    Common::File::exists("track01.ogg"))
		return;
#endif
#ifdef USE_FLAC
	if (Common::File::exists("track1.fla") ||
            Common::File::exists("track1.flac") ||
	    Common::File::exists("track01.fla") ||
	    Common::File::exists("track01.flac"))
		return;
#endif
#ifdef USE_MAD
	if (Common::File::exists("track1.mp3") ||
	    Common::File::exists("track01.mp3"))
		return;
#endif

	char buffer[MAXPATHLEN];
	int i;

	const Common::FSNode gameDataDir(ConfMan.get("path"));

	if (gameDataDir.getPath().empty()) {
		// That's it! I give up!
		if (getcwd(buffer, MAXPATHLEN) == NULL)
			return;
	} else
		Common::strlcpy(buffer, gameDataDir.getPath().c_str(), sizeof(buffer));

	for (i = 0; i < MAXPATHLEN - 1; i++) {
		if (buffer[i] == '\\')
			break;
	}

	buffer[i + 1] = 0;

	if (GetDriveType(buffer) == DRIVE_CDROM) {
		GUI::MessageDialog dialog(
			_("You appear to be playing this game directly\n"
			"from the CD. This is known to cause problems,\n"
			"and it is therefore recommended that you copy\n"
			"the data files to your hard disk instead.\n"
			"See the README file for details."), _("OK"));
		dialog.runModal();
	} else {
		// If we reached here, the game has audio tracks,
		// it's not ran from the CD and the tracks have not
		// been ripped.
		GUI::MessageDialog dialog(
			_("This game has audio tracks in its disk. These\n"
			"tracks need to be ripped from the disk using\n"
			"an appropriate CD audio extracting tool in\n"
			"order to listen to the game's music.\n"
			"See the README file for details."), _("OK"));
		dialog.runModal();
	}
#endif
}
Example #7
0
void POSIXSaveFileManager::checkPath(const Common::FSNode &dir) {
	const Common::String path = dir.getPath();
	clearError();

	struct stat sb;

	// Check whether the dir exists
	if (stat(path.c_str(), &sb) == -1) {
		// The dir does not exist, or stat failed for some other reason.
		// If the problem was that the path pointed to nothing, try
		// to create the dir (ENOENT case).
		switch (errno) {
		case EACCES:
			setError(Common::kWritePermissionDenied, "Search or write permission denied: "+path);
			break;
		case ELOOP:
			setError(Common::kUnknownError, "Too many symbolic links encountered while traversing the path: "+path);
			break;
		case ENAMETOOLONG:
			setError(Common::kUnknownError, "The path name is too long: "+path);
			break;
		case ENOENT:
			if (mkdir(path.c_str(), 0755) != 0) {
				// mkdir could fail for various reasons: The parent dir doesn't exist,
				// or is not writeable, the path could be completly bogus, etc.
				warning("mkdir for '%s' failed", path.c_str());
				perror("mkdir");

				switch (errno) {
				case EACCES:
					setError(Common::kWritePermissionDenied, "Search or write permission denied: "+path);
					break;
				case EMLINK:
					setError(Common::kUnknownError, "The link count of the parent directory would exceed {LINK_MAX}: "+path);
					break;
				case ELOOP:
					setError(Common::kUnknownError, "Too many symbolic links encountered while traversing the path: "+path);
					break;
				case ENAMETOOLONG:
					setError(Common::kUnknownError, "The path name is too long: "+path);
					break;
				case ENOENT:
					setError(Common::kPathDoesNotExist, "A component of the path does not exist, or the path is an empty string: "+path);
					break;
				case ENOTDIR:
					setError(Common::kPathDoesNotExist, "A component of the path prefix is not a directory: "+path);
					break;
				case EROFS:
					setError(Common::kWritePermissionDenied, "The parent directory resides on a read-only file system:"+path);
					break;
				}
			}
			break;
		case ENOTDIR:
			setError(Common::kPathDoesNotExist, "A component of the path prefix is not a directory: "+path);
			break;
		}
	} else {
		// So stat() succeeded. But is the path actually pointing to a directory?
		if (!S_ISDIR(sb.st_mode)) {
			setError(Common::kPathDoesNotExist, "The given savepath is not a directory: "+path);
		}
	}
}
Example #8
0
TestExitStatus CloudTests::testUploading() {
	ConfParams.setCloudTestCallbackCalled(false);
	ConfParams.setCloudTestErrorCallbackCalled(false);

	if (CloudMan.getCurrentStorage() == nullptr) {
		Testsuite::logPrintf("Couldn't find connected Storage\n");
		return kTestFailed;
	}

	Common::String info = "Testing Cloud Storage API upload() method.\n"
		"In this test we'll try to upload a 'test1/file.txt' file.";

	if (Testsuite::handleInteractiveInput(info, "OK", "Skip", kOptionRight)) {
		Testsuite::logPrintf("Info! Skipping test : upload()\n");
		return kTestSkipped;
	}

	if (!ConfParams.isGameDataFound()) {
		Testsuite::logPrintf("Info! Couldn't find the game data, so skipping test : upload()\n");
		return kTestSkipped;
	}

	const Common::String &path = ConfMan.get("path");
	Common::FSDirectory gameRoot(path);
	Common::FSDirectory *directory = gameRoot.getSubDirectory("test1");
	Common::FSNode node = directory->getFSNode().getChild("file.txt");
	delete directory;

	if (CloudMan.getCurrentStorage()->uploadStreamSupported()) {
		if (CloudMan.getCurrentStorage()->upload(
				Common::String(getRemoteTestPath()) + "/testfile.txt",
				node.createReadStream(),
				new Common::GlobalFunctionCallback<Cloud::Storage::UploadResponse>(&fileUploadedCallback),
				new Common::GlobalFunctionCallback<Networking::ErrorResponse>(&errorCallback)
			) == nullptr) {
			Testsuite::logPrintf("Warning! No Request is returned!\n");
		}
	} else {
		Common::String filepath = node.getPath();
		if (CloudMan.getCurrentStorage()->upload(
				Common::String(getRemoteTestPath()) + "/testfile.txt",
				filepath.c_str(),
				new Common::GlobalFunctionCallback<Cloud::Storage::UploadResponse>(&fileUploadedCallback),
				new Common::GlobalFunctionCallback<Networking::ErrorResponse>(&errorCallback)
			) == nullptr) {
			Testsuite::logPrintf("Warning! No Request is returned!\n");
		}
	}

	if (!waitForCallbackMore()) return kTestSkipped;
	Testsuite::clearScreen();

	if (ConfParams.isCloudTestErrorCallbackCalled()) {
		Testsuite::logPrintf("Error callback was called\n");
		return kTestFailed;
	}

	Common::String info2 = "upload() is finished. Do you want to list '/testbed' directory?";

	if (!Testsuite::handleInteractiveInput(info2, "Yes", "No", kOptionRight)) {
		ConfParams.setCloudTestCallbackCalled(false);

		if (CloudMan.listDirectory(
				getRemoteTestPath(),
				new Common::GlobalFunctionCallback<Cloud::Storage::FileArrayResponse>(&directoryListedCallback),
				new Common::GlobalFunctionCallback<Networking::ErrorResponse>(&errorCallback)
			) == nullptr) {
			Testsuite::logPrintf("Warning! No Request is returned!\n");
		}

		if (!waitForCallbackMore()) return kTestSkipped;
		Testsuite::clearScreen();

		if (ConfParams.isCloudTestErrorCallbackCalled()) {
			Testsuite::logPrintf("Error callback was called\n");
			return kTestFailed;
		}
	}

	if (Testsuite::handleInteractiveInput("Was the CloudMan able to upload into 'testbed/testfile.txt' file?", "Yes", "No", kOptionRight)) {
		Testsuite::logDetailedPrintf("Error! File was not uploaded!\n");
		return kTestFailed;
	}

	Testsuite::logDetailedPrintf("File was uploaded\n");
	return kTestPassed;
}
Example #9
0
// Based on AdvancedMetaEngine::detectGame
ADDetectedGames AdlMetaEngine::detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra) const {
	// We run the file-based detector first and then add to the returned list
	ADDetectedGames matched = AdvancedMetaEngine::detectGame(parent, allFiles, language, platform, extra);

	debug(3, "Starting disk image detection in dir '%s'", parent.getPath().c_str());

	FilePropertiesMap filesProps;
	bool gotAnyMatchesWithAllFiles = false;

	for (uint g = 0; gameDiskDescriptions[g].desc.gameId != 0; ++g) {
		ADDetectedGame game(&gameDiskDescriptions[g].desc);

		// Skip games that don't meet the language/platform/extra criteria
		if (language != Common::UNK_LANG && game.desc->language != Common::UNK_LANG) {
			if (game.desc->language != language && !(language == Common::EN_ANY && (game.desc->flags & ADGF_ADDENGLISH)))
				continue;
		}

		if (platform != Common::kPlatformUnknown && game.desc->platform != Common::kPlatformUnknown && game.desc->platform != platform)
			continue;

		if ((_flags & kADFlagUseExtraAsHint) && !extra.empty() && game.desc->extra != extra)
			continue;

		bool allFilesPresent = true;

		for (uint f = 0; game.desc->filesDescriptions[f].fileName; ++f) {
			const ADGameFileDescription &fDesc = game.desc->filesDescriptions[f];
			Common::String fileName;
			bool foundDiskImage = false;

			for (uint e = 0; e < ARRAYSIZE(diskImageExts); ++e) {
				if (diskImageExts[e].platform == game.desc->platform) {
					Common::String testFileName(fDesc.fileName);
					testFileName += diskImageExts[e].extension;

					if (addFileProps(allFiles, testFileName, filesProps)) {
						if (foundDiskImage) {
							warning("Ignoring '%s' (already found '%s')", testFileName.c_str(), fileName.c_str());
							filesProps.erase(testFileName);
						} else {
							foundDiskImage = true;
							fileName = testFileName;
						}
					}
				}
			}

			if (!foundDiskImage) {
				allFilesPresent = false;
				break;
			}

			game.matchedFiles[fileName] = filesProps[fileName];

			if (game.hasUnknownFiles)
				continue;

			if (fDesc.md5 && fDesc.md5 != filesProps[fileName].md5) {
				debug(3, "MD5 Mismatch. Skipping (%s) (%s)", fDesc.md5, filesProps[fileName].md5.c_str());
				game.hasUnknownFiles = true;
				continue;
			}

			if (fDesc.fileSize != -1 && fDesc.fileSize != filesProps[fileName].size) {
				debug(3, "Size Mismatch. Skipping");
				game.hasUnknownFiles = true;
				continue;
			}

			debug(3, "Matched file: %s", fileName.c_str());
		}

		if (allFilesPresent && !game.hasUnknownFiles) {
			debug(2, "Found game: %s (%s/%s) (%d)", game.desc->gameId, getPlatformDescription(game.desc->platform), getLanguageDescription(game.desc->language), g);
			gotAnyMatchesWithAllFiles = true;
			matched.push_back(game);
		} else {
			if (allFilesPresent && !gotAnyMatchesWithAllFiles) {
				if (matched.empty() || strcmp(matched.back().desc->gameId, game.desc->gameId) != 0)
					matched.push_back(game);
			}

			debug(5, "Skipping game: %s (%s/%s) (%d)", game.desc->gameId, getPlatformDescription(game.desc->platform), getLanguageDescription(game.desc->language), g);
		}
	}

	return matched;
}