Common::InSaveFile *DefaultSaveFileManager::openForLoading(const Common::String &filename) { // Ensure that the savepath is valid. If not, generate an appropriate error. Common::String savePathName = getSavePath(); checkPath(Common::FSNode(savePathName)); if (getError().getCode() != Common::kNoError) return 0; // recreate FSNode since checkPath may have changed/created the directory Common::FSNode savePath(savePathName); Common::FSNode file = savePath.getChild(filename); if (!file.exists()) return 0; // Open the file for reading Common::SeekableReadStream *sf = file.createReadStream(); return Common::wrapCompressedReadStream(sf); }
/** * This test creates a file testbed.out, writes a sample data and confirms if * it is same by reading the file again. */ TestExitStatus FStests::testWriteFile() { const Common::String &path = ConfMan.get("path"); Common::FSNode gameRoot(path); if (!gameRoot.exists()) { Testsuite::logPrintf("Couldn't open the game data directory %s", path.c_str()); return kTestFailed; } Common::FSNode fileToWrite = gameRoot.getChild("testbed.out"); Common::WriteStream *ws = fileToWrite.createWriteStream(); if (!ws) { Testsuite::logDetailedPrintf("Can't open writable file in game data dir\n"); return kTestFailed; } ws->writeString("ScummVM Rocks!"); ws->flush(); delete ws; Common::SeekableReadStream *rs = fileToWrite.createReadStream(); if (!rs) { Testsuite::logDetailedPrintf("Can't open recently written file testbed.out in game data dir\n"); return kTestFailed; } Common::String readFromFile = rs->readLine(); delete rs; if (readFromFile.equals("ScummVM Rocks!")) { // All good Testsuite::logDetailedPrintf("Data written and read correctly\n"); return kTestPassed; } return kTestFailed; }
bool WagFileParser::parse(const Common::FSNode &node) { WagProperty property; // Temporary property used for reading Common::SeekableReadStream *stream = NULL; // The file stream _parsedOk = false; // We haven't parsed the file yet stream = node.createReadStream(); // Open the file if (stream) { // Check that opening the file was succesful if (checkWagVersion(*stream)) { // Check that WinAGI version string is valid // It seems we've got a valid *.wag file so let's parse its properties from the start. stream->seek(0); // Rewind the stream if (!_propList.empty()) _propList.clear(); // Clear out old properties (If any) do { // Parse the properties if (property.read(*stream)) { // Read the property and check it was read ok _propList.push_back(property); // Add read property to properties list debug(4, "WagFileParser::parse: Read property with code %d, type %d, number %d, size %d, data \"%s\"", property.getCode(), property.getType(), property.getNumber(), property.getSize(), property.getData()); } else // Reading failed, let's bail out break; } while (!endOfProperties(*stream)); // Loop until the end of properties // File was parsed successfully only if we got to the end of properties // and all the properties were read successfully (Also the last). _parsedOk = endOfProperties(*stream) && property.readOk(); if (!_parsedOk) // Error parsing stream warning("Error parsing WAG file (%s). WAG file ignored", node.getPath().c_str()); } else // Invalid WinAGI version string or it couldn't be read warning("Invalid WAG file (%s) version or error reading it. WAG file ignored", node.getPath().c_str()); } else // Couldn't open file warning("Couldn't open WAG file (%s). WAG file ignored", node.getPath().c_str()); delete stream; return _parsedOk; }
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; }
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 = Common::GUIO_NONE; 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; } Common::ScopedPtr<ResourceManager> resMan(new ResourceManager()); assert(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 |= Common::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 (const ADGameDescription *)&s_fallbackDesc; }
Common::InSaveFile *Ps2SaveFileManager::openForLoading(const Common::String &filename) { Common::FSNode savePath(ConfMan.get("savepath")); // TODO: is this fast? Common::SeekableReadStream *sf; if (!savePath.exists() || !savePath.isDirectory()) return NULL; // _screen->wantAnim(true); if (_getDev(savePath) == MC_DEV) { // if (strncmp(savePath.getPath().c_str(), "mc0:", 4) == 0) { char path[32]; // FIXME : hack for indy4 iq-points if (filename == "iq-points") { mcCheck("mc0:ScummVM/indy4"); sprintf(path, "mc0:ScummVM/indy4/iq-points"); } // FIXME : hack for bs1 saved games else if (filename == "SAVEGAME.INF") { mcCheck("mc0:ScummVM/sword1"); sprintf(path, "mc0:ScummVM/sword1/SAVEGAME.INF"); } else { char temp[32]; printf("MC : filename = %s\n", filename.c_str()); strcpy(temp, filename.c_str()); // mcSplit(temp, game, ext); char *game = strdup(strtok(temp, ".")); char *ext = strdup(strtok(NULL, "*")); sprintf(path, "mc0:ScummVM/%s", game); // per game path // mcCheck(path); // needed on load ? sprintf(path, "mc0:ScummVM/%s/%s.sav", game, ext); free(game); free(ext); } Common::FSNode file(path); if (!file.exists()) return NULL; sf = file.createReadStream(); } else { Common::FSNode file = savePath.getChild(filename); if (!file.exists()) return NULL; sf = file.createReadStream(); } // _screen->wantAnim(false); return Common::wrapCompressedReadStream(sf); }
Common::SeekableReadStream *openDiskFile(const Common::String &filename) { uint32 prefixSize = 0; Common::SeekableReadStream *file = NULL; Common::String fixedFilename = filename; // Absolute path: TODO: Add specific fallbacks here. if (filename.contains(':')) { if (filename.hasPrefix("c:\\windows\\fonts\\")) { // East Side Story refers to "c:\windows\fonts\framd.ttf" fixedFilename = filename.c_str() + 17; } else { error("openDiskFile::Absolute path or invalid filename used in %s", filename.c_str()); } } // Try directly from SearchMan first Common::ArchiveMemberList files; SearchMan.listMatchingMembers(files, fixedFilename); for (Common::ArchiveMemberList::iterator it = files.begin(); it != files.end(); ++it) { if ((*it)->getName() == filename) { file = (*it)->createReadStream(); break; } } // File wasn't found in SearchMan, try to parse the path as a relative path. if (!file) { Common::FSNode searchNode = getNodeForRelativePath(filename); if (searchNode.exists() && !searchNode.isDirectory() && searchNode.isReadable()) { file = searchNode.createReadStream(); } } if (file) { uint32 magic1, magic2; magic1 = file->readUint32LE(); magic2 = file->readUint32LE(); bool compressed = false; if (magic1 == DCGF_MAGIC && magic2 == COMPRESSED_FILE_MAGIC) { compressed = true; } if (compressed) { uint32 dataOffset, compSize, uncompSize; dataOffset = file->readUint32LE(); compSize = file->readUint32LE(); uncompSize = file->readUint32LE(); byte *compBuffer = new byte[compSize]; if (!compBuffer) { error("Error allocating memory for compressed file '%s'", filename.c_str()); delete file; return NULL; } byte *data = new byte[uncompSize]; if (!data) { error("Error allocating buffer for file '%s'", filename.c_str()); delete[] compBuffer; delete file; return NULL; } file->seek(dataOffset + prefixSize, SEEK_SET); file->read(compBuffer, compSize); if (Common::uncompress(data, (unsigned long *)&uncompSize, compBuffer, compSize) != true) { error("Error uncompressing file '%s'", filename.c_str()); delete[] compBuffer; delete file; return NULL; } delete[] compBuffer; delete file; return new Common::MemoryReadStream(data, uncompSize, DisposeAfterUse::YES); } else { file->seek(0, SEEK_SET); return file; } return file; } return NULL; }
ZipArchive::ZipArchive(const Common::FSNode &node) { SeekableReadStream *stream = node.createReadStream(); _zipFile = unzOpen(stream); }
bool StyledTTFont::loadFont(const Common::String &fontName, int32 point) { Common::String newFontName; if (fontName.matchString("*times new roman*", true) || fontName.matchString("*times*", true)) { if ((_style & (STTF_BOLD | STTF_ITALIC)) == (STTF_BOLD | STTF_ITALIC)) newFontName = "timesbi.ttf"; else if (_style & STTF_BOLD) newFontName = "timesbd.ttf"; else if (_style & STTF_ITALIC) newFontName = "timesi.ttf"; else newFontName = "times.ttf"; } else if (fontName.matchString("*courier new*", true) || fontName.matchString("*courier*", true) || fontName.matchString("*ZorkDeath*", true)) { if ((_style & (STTF_BOLD | STTF_ITALIC)) == (STTF_BOLD | STTF_ITALIC)) newFontName = "courbi.ttf"; else if (_style & STTF_BOLD) newFontName = "courbd.ttf"; else if (_style & STTF_ITALIC) newFontName = "couri.ttf"; else newFontName = "cour.ttf"; } else if (fontName.matchString("*century schoolbook*", true)) { if ((_style & (STTF_BOLD | STTF_ITALIC)) == (STTF_BOLD | STTF_ITALIC)) newFontName = "censcbkbi.ttf"; else if (_style & STTF_BOLD) newFontName = "censcbkbd.ttf"; else if (_style & STTF_ITALIC) newFontName = "censcbki.ttf"; else newFontName = "censcbk.ttf"; } else if (fontName.matchString("*garamond*", true)) { if ((_style & (STTF_BOLD | STTF_ITALIC)) == (STTF_BOLD | STTF_ITALIC)) newFontName = "garabi.ttf"; else if (_style & STTF_BOLD) newFontName = "garabd.ttf"; else if (_style & STTF_ITALIC) newFontName = "garai.ttf"; else newFontName = "gara.ttf"; } else if (fontName.matchString("*arial*", true) || fontName.matchString("*ZorkNormal*", true)) { if ((_style & (STTF_BOLD | STTF_ITALIC)) == (STTF_BOLD | STTF_ITALIC)) newFontName = "arialbi.ttf"; else if (_style & STTF_BOLD) newFontName = "arialbd.ttf"; else if (_style & STTF_ITALIC) newFontName = "ariali.ttf"; else newFontName = "arial.ttf"; } else { debug("Could not identify font: %s. Reverting to Arial", fontName.c_str()); newFontName = "arial.ttf"; } bool sharp = (_style & STTF_SHARP) == STTF_SHARP; Common::File *file = _engine->getSearchManager()->openFile(newFontName); if (!file) { Common::SeekableReadStream *themeFile = nullptr; if (ConfMan.hasKey("themepath")) { Common::FSNode themePath(ConfMan.get("themepath")); if (themePath.exists()) { Common::FSNode scummModern = themePath.getChild("scummmodern.zip"); if (scummModern.exists()) { themeFile = scummModern.createReadStream(); } } } if (!themeFile) { // Fallback : Search for ScummModern.zip in SearchMan. themeFile = SearchMan.createReadStreamForMember("scummmodern.zip"); } if (themeFile) { Common::Archive *themeArchive = Common::makeZipArchive(themeFile); if (themeArchive->hasFile("FreeSans.ttf")) { Common::SeekableReadStream *stream = nullptr; stream = themeArchive->createReadStreamForMember("FreeSans.ttf"); Graphics::Font *_newFont = Graphics::loadTTFFont(*stream, point, 60, (sharp ? Graphics::kTTFRenderModeMonochrome : Graphics::kTTFRenderModeNormal)); // 66 dpi for 640 x 480 on 14" display if (_newFont) { if (!_font) delete _font; _font = _newFont; } if (stream) delete stream; } delete themeArchive; themeArchive = nullptr; } } else { Graphics::Font *_newFont = Graphics::loadTTFFont(*file, point, 60, (sharp ? Graphics::kTTFRenderModeMonochrome : Graphics::kTTFRenderModeNormal)); // 66 dpi for 640 x 480 on 14" display if (_newFont) { if (!_font) delete _font; _font = _newFont; } delete file; } _fntName = fontName; _lineHeight = point; if (_font) return true; return false; }
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; }