bool SavePartInfo::write(Common::WriteStream &stream) const { if (!_header.write(stream)) return false; stream.writeUint32LE(_gameID); stream.writeUint32LE(_gameVersion); stream.writeByte(_endian); stream.writeUint32LE(_varCount); stream.writeUint32LE(_descMaxLength); if (stream.write(_desc, _descMaxLength) != _descMaxLength) return false; return flushStream(stream); }
bool LureEngine::saveGame(uint8 slotNumber, Common::String &caption) { Common::WriteStream *f = this->_saveFileMan->openForSaving( generateSaveName(slotNumber)); if (f == NULL) return false; f->write("lure", 5); f->writeByte(getLanguage()); f->writeByte(LURE_SAVEGAME_MINOR); f->writeString(caption); f->writeByte(0); // End of string terminator Resources::getReference().saveToStream(f); Game::getReference().saveToStream(f); Sound.saveToStream(f); Fights.saveToStream(f); Room::getReference().saveToStream(f); delete f; return true; }
void Decompiler::writeBlock(Common::WriteStream &out, const Block *block, size_t indent) { for (const auto instruction : block->instructions) { writeInstruction(out, instruction, indent); } for (const auto &childType : block->childrenTypes) { if (isSubRoutineCall(childType)) { writeIndent(out, indent); const Instruction *instruction = block->instructions.back(); out.writeString(formatJumpLabelName(*instruction->branches[0])); out.writeString("("); for (size_t i = 0; i < instruction->variables.size(); ++i) { out.writeString(formatVariableName(instruction->variables[i])); if (i < instruction->variables.size() - 1) out.writeString(", "); } out.writeString(");\n"); writeBlock(out, block->children[1], indent); } } for (const auto &control : block->controls) { if (control.type == kControlTypeReturn) { writeIndent(out, indent); out.writeString("return;\n"); } else if (control.type == kControlTypeIfCond) { writeIfControl(out, control, indent); } // TODO: while // TODO: break // TODO: continue } }
reg_t kFileIOExists(EngineState *s, int argc, reg_t *argv) { Common::String name = s->_segMan->getString(argv[0]); #ifdef ENABLE_SCI32 // Cache the file existence result for the Phantasmagoria // save index file, as the game scripts keep checking for // its existence. if (name == PHANTASMAGORIA_SAVEGAME_INDEX && s->_virtualIndexFile) return TRUE_REG; #endif bool exists = false; // Check for regular file exists = Common::File::exists(name); // Check for a savegame with the name Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager(); if (!exists) exists = !saveFileMan->listSavefiles(name).empty(); // Try searching for the file prepending "target-" const Common::String wrappedName = g_sci->wrapFilename(name); if (!exists) { exists = !saveFileMan->listSavefiles(wrappedName).empty(); } // SCI2+ debug mode if (DebugMan.isDebugChannelEnabled(kDebugLevelDebugMode)) { if (!exists && name == "1.scr") // PQ4 exists = true; if (!exists && name == "18.scr") // QFG4 exists = true; if (!exists && name == "99.scr") // GK1, KQ7 exists = true; if (!exists && name == "classes") // GK2, SQ6, LSL7 exists = true; } // Special case for non-English versions of LSL5: The English version of // LSL5 calls kFileIO(), case K_FILEIO_OPEN for reading to check if // memory.drv exists (which is where the game's password is stored). If // it's not found, it calls kFileIO() again, case K_FILEIO_OPEN for // writing and creates a new file. Non-English versions call kFileIO(), // case K_FILEIO_FILE_EXISTS instead, and fail if memory.drv can't be // found. We create a default memory.drv file with no password, so that // the game can continue. if (!exists && name == "memory.drv") { // Create a new file, and write the bytes for the empty password // string inside byte defaultContent[] = { 0xE9, 0xE9, 0xEB, 0xE1, 0x0D, 0x0A, 0x31, 0x30, 0x30, 0x30 }; Common::WriteStream *outFile = saveFileMan->openForSaving(wrappedName); for (int i = 0; i < 10; i++) outFile->writeByte(defaultContent[i]); outFile->finalize(); exists = !outFile->err(); // check whether we managed to create the file. delete outFile; } // Special case for KQ6 Mac: The game checks for two video files to see // if they exist before it plays them. Since we support multiple naming // schemes for resource fork files, we also need to support that here in // case someone has a "HalfDome.bin" file, etc. if (!exists && g_sci->getGameId() == GID_KQ6 && g_sci->getPlatform() == Common::kPlatformMacintosh && (name == "HalfDome" || name == "Kq6Movie")) exists = Common::MacResManager::exists(name); debugC(kDebugLevelFile, "kFileIO(fileExists) %s -> %d", name.c_str(), exists); return make_reg(0, exists); }
static void saveOrLoadPtr(Common::WriteStream &stream, int16 *&p, int16 *base) { int32 offset = (int32)(p - base); stream.writeSint32LE(offset); }
static void saveOrLoad(Common::WriteStream &stream, int16 &i) { stream.writeSint16LE(i); }
void TwoDAFile::writeCSV(Common::WriteStream &out) const { // Write column headers for (size_t i = 0; i < _headers.size(); i++) { const bool needQuote = _headers[i].contains(','); if (needQuote) out.writeByte('"'); out.writeString(_headers[i]); if (needQuote) out.writeByte('"'); if (i < (_headers.size() - 1)) out.writeByte(','); } out.writeByte('\n'); // Write array for (size_t i = 0; i < _rows.size(); i++) { for (size_t j = 0; j < _rows[i]->_data.size(); j++) { const bool needQuote = _rows[i]->_data[j].contains(','); if (needQuote) out.writeByte('"'); if (_rows[i]->_data[j] != "****") out.writeString(_rows[i]->_data[j]); if (needQuote) out.writeByte('"'); if (j < (_rows[i]->_data.size() - 1)) out.writeByte(','); } out.writeByte('\n'); } out.flush(); }
void pngWriteToStream(png_structp pngPtr, png_bytep data, png_size_t length) { void *writeIOptr = png_get_io_ptr(pngPtr); Common::WriteStream *stream = (Common::WriteStream *)writeIOptr; stream->write(data, length); }
bool err() const { // CHECKME: does Z_STREAM_END make sense here? return (_zlibErr != Z_OK && _zlibErr != Z_STREAM_END) || _wrapped->err(); }
void MainWindow::exportWAVImpl(Sound::AudioStream *sound, Common::WriteStream &wav) { assert(sound); const uint16 channels = sound->getChannels(); const uint32 rate = sound->getRate(); std::deque<SoundBuffer> buffers; uint64 length = getSoundLength(sound); if (length != Sound::RewindableAudioStream::kInvalidLength) buffers.resize((length / (SoundBuffer::kBufferSize / channels)) + 1); uint32 samples = 0; std::deque<SoundBuffer>::iterator buffer = buffers.begin(); while (!sound->endOfStream()) { if (buffer == buffers.end()) { buffers.push_back(SoundBuffer()); buffer = --buffers.end(); } buffer->samples = sound->readBuffer(buffer->buffer, SoundBuffer::kBufferSize); if (buffer->samples > 0) samples += buffer->samples; ++buffer; } samples /= channels; const uint32 dataSize = samples * channels * 2; const uint32 byteRate = rate * channels * 2; const uint16 blockAlign = channels * 2; wav.writeUint32BE(MKTAG('R', 'I', 'F', 'F')); wav.writeUint32LE(36 + dataSize); wav.writeUint32BE(MKTAG('W', 'A', 'V', 'E')); wav.writeUint32BE(MKTAG('f', 'm', 't', ' ')); wav.writeUint32LE(16); wav.writeUint16LE(1); wav.writeUint16LE(channels); wav.writeUint32LE(rate); wav.writeUint32LE(byteRate); wav.writeUint16LE(blockAlign); wav.writeUint16LE(16); wav.writeUint32BE(MKTAG('d', 'a', 't', 'a')); wav.writeUint32LE(dataSize); for (std::deque<SoundBuffer>::const_iterator b = buffers.begin(); b != buffers.end(); ++b) for (int i = 0; i < b->samples; i++) wav.writeUint16LE(b->buffer[i]); }
static void decompress00(Common::SeekableReadStream &small, Common::WriteStream &out, uint32 size) { out.writeStream(small, size); }
void Decompiler::writeIndent(Common::WriteStream &out, size_t indent) { for (size_t i = 0; i < indent; ++i) out.writeString("\t"); }
void Decompiler::writeInstruction(Common::WriteStream &out, const Instruction* instruction, size_t indent) { switch (instruction->opcode) { case kOpcodeCONST: { const Variable *v = instruction->variables[0]; writeIndent(out, indent); out.writeString(getVariableTypeName(v->type) + " " + formatVariableName(v) + " = " + formatInstructionData(*instruction) + ";\n"); break; } case kOpcodeACTION: { unsigned int paramCount = instruction->args[1]; writeIndent(out, indent); if (instruction->variables.size() > paramCount) { const Variable *ret = instruction->variables.back(); out.writeString(getVariableTypeName(ret->type, _ncs->getGame()) + " " + formatVariableName(ret) + " = "); } out.writeString(getFunctionName(_ncs->getGame(), instruction->args[0])); out.writeString("("); for (unsigned int i = 0; i < paramCount; ++i) { out.writeString(formatVariableName(instruction->variables[i])); if (i < paramCount - 1) out.writeString(", "); } out.writeString(");\n"); break; } case kOpcodeCPDOWNBP: case kOpcodeCPDOWNSP: case kOpcodeCPTOPBP: case kOpcodeCPTOPSP: { const Variable *v1 = instruction->variables[0]; const Variable *v2 = instruction->variables[1]; writeIndent(out, indent); out.writeString(getVariableTypeName(v2->type, _ncs->getGame()) + " " + formatVariableName(v2) + " = " + formatVariableName(v1) + ";\n"); break; } case kOpcodeLOGAND: { const Variable *v1 = instruction->variables[0]; const Variable *v2 = instruction->variables[1]; const Variable *result = instruction->variables[2]; writeIndent(out, indent); out.writeString( getVariableTypeName(result->type, _ncs->getGame()) + " " + formatVariableName(result) + " = " + formatVariableName(v1) + " && " + formatVariableName(v2) + ";\n" ); break; } case kOpcodeLOGOR: { const Variable *v1 = instruction->variables[0]; const Variable *v2 = instruction->variables[1]; const Variable *result = instruction->variables[2]; writeIndent(out, indent); out.writeString( getVariableTypeName(result->type, _ncs->getGame()) + " " + formatVariableName(result) + " = " + formatVariableName(v1) + " || " + formatVariableName(v2) + ";\n" ); break; } case kOpcodeEQ: { const Variable *v1 = instruction->variables[0]; const Variable *v2 = instruction->variables[1]; const Variable *result = instruction->variables[2]; writeIndent(out, indent); out.writeString( getVariableTypeName(result->type, _ncs->getGame()) + " " + formatVariableName(result) + " = " + formatVariableName(v1) + " == " + formatVariableName(v2) + ";\n" ); break; } case kOpcodeLEQ: { const Variable *v1 = instruction->variables[0]; const Variable *v2 = instruction->variables[1]; const Variable *result = instruction->variables[2]; writeIndent(out, indent); out.writeString( getVariableTypeName(result->type, _ncs->getGame()) + " " + formatVariableName(result) + " = " + formatVariableName(v1) + " <= " + formatVariableName(v2) + ";\n" ); break; } case kOpcodeLT: { const Variable *v1 = instruction->variables[0]; const Variable *v2 = instruction->variables[1]; const Variable *result = instruction->variables[2]; writeIndent(out, indent); out.writeString( getVariableTypeName(result->type, _ncs->getGame()) + " " + formatVariableName(result) + " = " + formatVariableName(v1) + " < " + formatVariableName(v2) + ";\n" ); break; } case kOpcodeGEQ: { const Variable *v1 = instruction->variables[0]; const Variable *v2 = instruction->variables[1]; const Variable *result = instruction->variables[2]; writeIndent(out, indent); out.writeString( getVariableTypeName(result->type, _ncs->getGame()) + " " + formatVariableName(result) + " = " + formatVariableName(v1) + " >= " + formatVariableName(v2) + ";\n" ); break; } case kOpcodeGT: { const Variable *v1 = instruction->variables[0]; const Variable *v2 = instruction->variables[1]; const Variable *result = instruction->variables[2]; writeIndent(out, indent); out.writeString( getVariableTypeName(result->type, _ncs->getGame()) + " " + formatVariableName(result) + " = " + formatVariableName(v1) + " > " + formatVariableName(v2) + ";\n" ); break; } case kOpcodeNOT: { const Variable *v = instruction->variables[0]; const Variable *result = instruction->variables[1]; writeIndent(out, indent); out.writeString( getVariableTypeName(result->type, _ncs->getGame()) + " " + formatVariableName(result) + " = " + "!" + formatVariableName(v) + ";\n" ); break; } case kOpcodeRSADD: { const Variable *v = instruction->variables[0]; writeIndent(out, indent); out.writeString( getVariableTypeName(v->type, _ncs->getGame()) + " " + formatVariableName(v) + " = " ); switch (v->type) { case kTypeString: out.writeString("\"\""); break; case kTypeInt: out.writeString("0"); break; case kTypeFloat: out.writeString("0.0"); break; default: // TODO: No idea how empty objects or engine types are intialized. out.writeString("0"); break; } out.writeString(";\n"); break; } // TODO: Not all necessary instruction are implemented here default: break; } }
void disNCS(const Common::UString &inFile, const Common::UString &outFile, Aurora::GameID &game, Command &command, bool printStack, bool printControlTypes) { Common::SeekableReadStream *ncs = new Common::ReadFile(inFile); Common::WriteStream *out = 0; try { if (!outFile.empty()) out = new Common::WriteFile(outFile); else out = new Common::StdOutStream; status("Disassembling script..."); NWScript::Disassembler disassembler(*ncs, game); if (game != Aurora::kGameIDUnknown) { try { status("Analyzing script stack..."); disassembler.analyzeStack(); } catch (...) { Common::exceptionDispatcherWarnAndIgnore("Script analysis failed"); } try { status("Analyzing control flow..."); disassembler.analyzeControlFlow(); } catch (...) { Common::exceptionDispatcherWarnAndIgnore("Control flow analysis failed"); } } switch (command) { case kCommandListing: disassembler.createListing(*out, printStack); break; case kCommandAssembly: disassembler.createAssembly(*out, printStack); break; case kCommandDot: disassembler.createDot(*out, printControlTypes); break; default: throw Common::Exception("Invalid command %u", (uint)command); } } catch (...) { delete ncs; delete out; throw; } out->flush(); if (!outFile.empty()) status("Disassembled \"%s\" into \"%s\"", inFile.c_str(), outFile.c_str()); delete ncs; delete out; }
void GameState::writeState(uint32 sceneId, uint32 threadId) { Common::WriteStream *writeStream = newWriteStream(); writeStream->writeUint32LE(sceneId); writeStream->writeUint32LE(threadId); writeStateInternal(writeStream); }
void clearErr() { // Note: we don't reset the _zlibErr here, as it is not // clear in general how _wrapped->clearErr(); }
int ObjectV2::save(Common::WriteStream &dest) { dest.write(_objData, _objSize); return 0; }
void TwoDAFile::writeBinary(Common::WriteStream &out) const { const size_t columnCount = _headers.size(); const size_t rowCount = _rows.size(); const size_t cellCount = columnCount * rowCount; out.writeString("2DA V2.b\n"); // Write the column headers for (std::vector<Common::UString>::const_iterator h = _headers.begin(); h != _headers.end(); ++h) { out.writeString(*h); out.writeByte('\t'); } out.writeByte('\0'); // Write the row indices out.writeUint32LE((uint32) rowCount); for (size_t i = 0; i < rowCount; i++) { out.writeString(Common::composeString(i)); out.writeByte('\t'); } /* Deduplicate cell data strings. Binary 2DA files don't store the * data for each cell directly: instead, each cell contains an offset * into a data array. This way, cells with the same data only need to * to store this data once. * * The original binary 2DA files in KotOR/KotOR2 make extensive use * of that, and we should do this as well. * * Basically, this involves going through each cell, and looking up * if we already saved this particular piece of data. If not, save * it, otherwise only remember the offset. There's no need to be * particularly smart about it, so we're just doing it the naive * O(n^2) way. */ std::vector<Common::UString> data; std::vector<size_t> offsets; data.reserve(cellCount); offsets.reserve(cellCount); size_t dataSize = 0; std::vector<size_t> cells; cells.reserve(cellCount); for (size_t i = 0; i < rowCount; i++) { assert(_rows[i]); for (size_t j = 0; j < columnCount; j++) { const Common::UString cell = _rows[i]->getString(j); // Do we already know about this cell data string? size_t foundCell = SIZE_MAX; for (size_t k = 0; k < data.size(); k++) { if (data[k] == cell) { foundCell = k; break; } } // If not, add it to the cell data array if (foundCell == SIZE_MAX) { foundCell = data.size(); data.push_back(cell); offsets.push_back(dataSize); dataSize += data.back().size() + 1; if (dataSize > 65535) throw Common::Exception("TwoDAFile::writeBinary(): Cell data size overflow"); } // Remember the offset to the cell data array cells.push_back(offsets[foundCell]); } } // Write cell data offsets for (std::vector<size_t>::const_iterator c = cells.begin(); c != cells.end(); ++c) out.writeUint16LE((uint16) *c); // Size of the all cell data strings out.writeUint16LE((uint16) dataSize); // Write cell data strings for (std::vector<Common::UString>::const_iterator d = data.begin(); d != data.end(); ++d) { out.writeString(*d); out.writeByte('\0'); } }
void pngFlushStream(png_structp pngPtr) { void *writeIOptr = png_get_io_ptr(pngPtr); Common::WriteStream *stream = (Common::WriteStream *)writeIOptr; stream->flush(); }
// This function leaks. For now I don't care bool PspUnitTests::testFileSystem() { // create memory const uint32 BufSize = 32 * 1024; char* buffer = new char[BufSize]; int i; Common::WriteStream *wrStream; Common::SeekableReadStream *rdStream; PSP_INFO_PRINT("testing fileSystem...\n"); // fill buffer for (i=0; i<(int)BufSize; i += 4) { buffer[i] = 'A'; buffer[i + 1] = 'B'; buffer[i + 2] = 'C'; buffer[i + 3] = 'D'; } // create a file const char *path = "./file.test"; Common::FSNode file(path); PSP_INFO_PRINT("creating write stream...\n"); wrStream = file.createWriteStream(); if (!wrStream) { PSP_ERROR("%s couldn't be created.\n", path); return false; } // write contents char* index = buffer; int32 totalLength = BufSize; int32 curLength = 50; PSP_INFO_PRINT("writing...\n"); while(totalLength - curLength > 0) { if ((int)wrStream->write(index, curLength) != curLength) { PSP_ERROR("couldn't write %d bytes\n", curLength); return false; } totalLength -= curLength; index += curLength; //curLength *= 2; //PSP_INFO_PRINT("write\n"); } // write the rest if ((int)wrStream->write(index, totalLength) != totalLength) { PSP_ERROR("couldn't write %d bytes\n", curLength); return false; } delete wrStream; PSP_INFO_PRINT("reading...\n"); rdStream = file.createReadStream(); if (!rdStream) { PSP_ERROR("%s couldn't be created.\n", path); return false; } // seek to beginning if (!rdStream->seek(0, SEEK_SET)) { PSP_ERROR("couldn't seek to the beginning after writing the file\n"); return false; } // read the contents char *readBuffer = new char[BufSize + 4]; memset(readBuffer, 0, (BufSize + 4)); index = readBuffer; while (rdStream->read(index, 100) == 100) { index += 100; } if (!rdStream->eos()) { PSP_ERROR("didn't find EOS at end of stream\n"); return false; } // compare for (i=0; i<(int)BufSize; i++) if (buffer[i] != readBuffer[i]) { PSP_ERROR("reading/writing mistake at %x. Got %x instead of %x\n", i, readBuffer[i], buffer[i]); return false; } // Check for exceeding limit for (i=0; i<4; i++) { if (readBuffer[BufSize + i]) { PSP_ERROR("read exceeded limits. %d = %x\n", BufSize + i, readBuffer[BufSize + i]); } } delete rdStream; PSP_INFO_PRINT("writing...\n"); wrStream = file.createWriteStream(); if (!wrStream) { PSP_ERROR("%s couldn't be created.\n", path); return false; } const char *phrase = "Jello is really fabulous"; uint32 phraseLen = strlen(phrase); int ret; if ((ret = wrStream->write(phrase, phraseLen)) != (int)phraseLen) { PSP_ERROR("couldn't write phrase. Got %d instead of %d\n", ret, phraseLen); return false; } PSP_INFO_PRINT("reading...\n"); delete wrStream; rdStream = file.createReadStream(); if (!rdStream) { PSP_ERROR("%s couldn't be created.\n", path); return false; } char *readPhrase = new char[phraseLen + 2]; memset(readPhrase, 0, phraseLen + 2); if ((ret = rdStream->read(readPhrase, phraseLen) != phraseLen)) { PSP_ERROR("read error on phrase. Got %d instead of %d\n", ret, phraseLen); return false; } for (i=0; i<(int)phraseLen; i++) { if (readPhrase[i] != phrase[i]) { PSP_ERROR("bad read/write in phrase. At %d, %x != %x\n", i, readPhrase[i], phrase[i]); return false; } } // check for exceeding if (readPhrase[i] != 0) { PSP_ERROR("found excessive copy in phrase. %c at %d\n", readPhrase[i], i); return false; } PSP_INFO_PRINT("trying to read end...\n"); // seek to end if (!rdStream->seek(0, SEEK_END)) { PSP_ERROR("couldn't seek to end for append\n"); return false; }; // try to read if (rdStream->read(readPhrase, 2) || !rdStream->eos()) { PSP_ERROR("was able to read at end of file\n"); return false; } PSP_INFO_PRINT("ok\n"); return true; }