void FoxPro::setMemo(size_t record, size_t field, SeekableReadStream *value) { assert((record < _records.size()) && (field < _fields.size())); Record &r = _records[record]; Field &f = _fields[field]; if (f.type != kTypeMemo) throw Exception("Field is not of memo type ('%c')", f.type); char *data = (char *) r.fields[field]; if (!value) { memset(data, 0x20, f.size); updateUpdate(); return; } value->seek(0); size_t size = value->size(); size_t block = _memos.size(); _memos.push_back(new byte[_memoBlockSize]); size_t startBlock = block + 1; WRITE_BE_UINT32(_memos[block] , 1); WRITE_BE_UINT32(_memos[block] + 4, size); bool first = true; while (size > 0) { size_t n = MIN<size_t>(size, _memoBlockSize - (first ? 8 : 0)); if (value->read(_memos[block] + (first ? 8 : 0), n) != n) throw Exception(kReadError); size -= n; block += 1; if (size > 0) _memos.push_back(new byte[_memoBlockSize]); first = false; } if (f.decimals != 0) snprintf(data, f.size, "%*u", f.size, (uint) startBlock); else snprintf(data, f.size, "%*.*f", f.size, f.decimals, (double) startBlock); updateUpdate(); }
bool createIDMap(PAKFile &out, const ExtractInformation *eI, const int *needList) { int dataEntries = 0; // Count entries in the need list for (const int *n = needList; *n != -1; ++n) ++dataEntries; const int mapSize = 2 + dataEntries * (2 + 1 + 4); uint8 *map = new uint8[mapSize]; uint8 *dst = map; WRITE_BE_UINT16(dst, dataEntries); dst += 2; for (const int *id = needList; *id != -1; ++id) { WRITE_BE_UINT16(dst, *id); dst += 2; const ExtractFilename *fDesc = getFilenameDesc(*id); if (!fDesc) return false; *dst++ = getTypeID(fDesc->type); WRITE_BE_UINT32(dst, getFilename(eI, *id)); dst += 4; } char filename[12]; if (!getFilename(filename, eI, 0)) { fprintf(stderr, "ERROR: Could not create ID map for game\n"); return false; } out.removeFile(filename); if (!out.addFile(filename, map, mapSize)) { fprintf(stderr, "ERROR: Could not add ID map \"%s\" to kyra.dat\n", filename); return false; } return true; }
int main(int argc, char *argv[]) { if (argc != 2) { printHelp(argv[0]); return -1; } PAKFile out; // First step: Write out all resources. outputAllResources(out); // Second step: Write all game version information std::vector<GameDef> games; outputAllGames(out, games); // Third step: Write index file byte *const indexBuffer = new byte[8 + 2 * games.size()]; byte *dst = indexBuffer; WRITE_BE_UINT32(dst, kKyraDatVersion); dst += 4; WRITE_BE_UINT32(dst, games.size()); dst += 4; for (std::vector<GameDef>::const_iterator i = games.begin(), end = games.end(); i != end; ++i) { WRITE_BE_UINT16(dst, *i); dst += 2; } if (!out.addFile("INDEX", indexBuffer, 8 + 2 * games.size())) { error("couldn't write INDEX file"); } if (!out.saveFile(argv[1])) { error("couldn't save changes to '%s'", argv[1]); } uint8 digest[16]; if (!md5_file(argv[1], digest, 0)) error("couldn't calc. md5 for file '%s'", argv[1]); FILE *f = fopen(argv[1], "ab"); if (!f) error("couldn't open file '%s'", argv[1]); if (fwrite(digest, 1, 16, f) != 16) error("couldn't write md5sum to file '%s'", argv[1]); fclose(f); return 0; }
bool updateIndex(PAKFile &out, const ExtractInformation *eI) { uint32 size = 0; const uint8 *data = out.getFileData("INDEX", &size); Index index; if (data) index = parseIndex(data, size); GameDef gameDef = createGameDef(eI); if (index.version == kKyraDatVersion) { if (std::find(index.gameList.begin(), index.gameList.end(), gameDef) == index.gameList.end()) { ++index.includedGames; index.gameList.push_back(gameDef); } else { // Already included in the game list, thus we do not need any further processing here. return true; } } else { index.version = kKyraDatVersion; index.includedGames = 1; index.gameList.push_back(gameDef); } const uint32 indexBufferSize = 8 + index.includedGames * 2; uint8 *indexBuffer = new uint8[indexBufferSize]; assert(indexBuffer); uint8 *dst = indexBuffer; WRITE_BE_UINT32(dst, index.version); dst += 4; WRITE_BE_UINT32(dst, index.includedGames); dst += 4; for (Index::GameList::const_iterator i = index.gameList.begin(); i != index.gameList.end(); ++i) { WRITE_BE_UINT16(dst, *i); dst += 2; } out.removeFile("INDEX"); if (!out.addFile("INDEX", indexBuffer, indexBufferSize)) { fprintf(stderr, "ERROR: couldn't update kyra.dat INDEX\n"); delete[] indexBuffer; return false; } return true; }
bool createIDMap(PAKFile &out, const Game *g, const int *needList) { int dataEntries = 0; // Count entries in the need list and check whether the resources are // present for (const int *n = needList; *n != -1; ++n) { char filename[12]; if (!getFilename(filename, g, *n) || !out.getFileList()->findEntry(filename)) { fprintf(stderr, "ERROR: Could not find need %d for game %04X", *n, createGameDef(g)); return false; } ++dataEntries; } const int mapSize = 2 + dataEntries * (2 + 1 + 4); uint8 *map = new uint8[mapSize]; uint8 *dst = map; WRITE_BE_UINT16(dst, dataEntries); dst += 2; for (const int *id = needList; *id != -1; ++id) { WRITE_BE_UINT16(dst, *id); dst += 2; const ExtractFilename *fDesc = getFilenameDesc(*id); if (!fDesc) { delete[] map; return false; } *dst++ = fDesc->type; WRITE_BE_UINT32(dst, getFilename(g, *id)); dst += 4; } char filename[12]; if (!getFilename(filename, g, 0)) { fprintf(stderr, "ERROR: Could not create ID map for game\n"); delete[] map; return false; } if (!out.addFile(filename, map, mapSize)) { fprintf(stderr, "ERROR: Could not add ID map \"%s\" to kyra.dat\n", filename); delete[] map; return false; } return true; }
Common::ErrorCode Blorb::load() { // First, chew through the file and index the chunks Common::File f; if (!f.open(_filename) || f.size() < 12) return Common::kReadingFailed; if (f.readUint32BE() != ID_FORM) return Common::kReadingFailed; f.readUint32BE(); if (f.readUint32BE() != ID_IFRS) return Common::kReadingFailed; if (f.readUint32BE() != ID_RIdx) return Common::kReadingFailed; f.readUint32BE(); uint count = f.readUint32BE(); // First read in the resource index for (uint idx = 0; idx < count; ++idx) { ChunkEntry ce; ce._type = f.readUint32BE(); ce._number = f.readUint32BE(); ce._offset = f.readUint32BE(); _chunks.push_back(ce); } // Further iterate through the resources for (uint idx = 0; idx < _chunks.size(); ++idx) { ChunkEntry &ce = _chunks[idx]; f.seek(ce._offset); ce._offset += 8; ce._id = f.readUint32BE(); ce._size = f.readUint32BE(); if (ce._type == ID_Pict) { ce._filename = Common::String::format("pic%u", ce._number); if (ce._id == ID_JPEG) ce._filename += ".jpg"; else if (ce._id == ID_PNG) ce._filename += ".png"; else if (ce._id == ID_Rect) ce._filename += ".rect"; } else if (ce._type == ID_Snd) { ce._filename = Common::String::format("sound%u", ce._number); if (ce._id == ID_MIDI) ce._filename += ".midi"; else if (ce._id == ID_MP3) ce._filename += ".mp3"; else if (ce._id == ID_WAVE) ce._filename += ".wav"; else if (ce._id == ID_AIFF || ce._id == ID_FORM) ce._filename += ".aiff"; else if (ce._id == ID_OGG) ce._filename += ".ogg"; else if (ce._id == ID_MOD) ce._filename += ".mod"; } else if (ce._type == ID_Data) { ce._filename = Common::String::format("data%u", ce._number); } else if (ce._type == ID_Exec) { char buffer[5]; WRITE_BE_UINT32(buffer, ce._id); buffer[4] = '\0'; Common::String type(buffer); if ( (_interpType == INTERPRETER_FROTZ && type == "ZCOD") || (_interpType == INTERPRETER_GLULXE && type == "GLUL") || (_interpType == INTERPRETER_TADS2 && type == "TAD2") || (_interpType == INTERPRETER_TADS3 && type == "TAD3") || (_interpType == INTERPRETER_HUGO && type == "HUGO") ) { // Game executable ce._filename = "game"; } else { ce._filename = type; } } } return Common::kNoError; }
void glopTexImage2D(GLContext *c, GLParam *p) { int target = p[1].i; int level = p[2].i; int components = p[3].i; int width = p[4].i; int height = p[5].i; int border = p[6].i; int format = p[7].i; int type = p[8].i; byte *pixels = (byte *)p[9].p; GLImage *im; byte *pixels1; bool do_free_after_rgb2rgba = false; Graphics::PixelFormat sourceFormat; switch (format) { case TGL_RGBA: sourceFormat = Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24); break; case TGL_RGB: sourceFormat = Graphics::PixelFormat(3, 8, 8, 8, 0, 0, 8, 16, 0); break; case TGL_BGRA: sourceFormat = Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24); break; case TGL_BGR: sourceFormat = Graphics::PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0); break; default: error("tglTexImage2D: Pixel format not handled."); } Graphics::PixelFormat pf; switch (format) { case TGL_RGBA: case TGL_RGB: #if defined(SCUMM_BIG_ENDIAN) pf = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0); #elif defined(SCUMM_LITTLE_ENDIAN) pf = Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24); #endif break; case TGL_BGRA: case TGL_BGR: #if defined(SCUMM_BIG_ENDIAN) pf = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 0, 8, 16); #elif defined(SCUMM_LITTLE_ENDIAN) pf = Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24); #endif break; default: break; } int bytes = pf.bytesPerPixel; // Simply unpack RGB into RGBA with 255 for Alpha. // FIXME: This will need additional checks when we get around to adding 24/32-bit backend. if (target == TGL_TEXTURE_2D && level == 0 && components == 3 && border == 0 && pixels != NULL) { if (format == TGL_RGB || format == TGL_BGR) { Graphics::PixelBuffer temp(pf, width * height, DisposeAfterUse::NO); Graphics::PixelBuffer pixPtr(sourceFormat, pixels); for (int i = 0; i < width * height; ++i) { uint8 r, g, b; pixPtr.getRGBAt(i, r, g, b); temp.setPixelAt(i, 255, r, g, b); } pixels = temp.getRawBuffer(); do_free_after_rgb2rgba = true; } } else if ((format != TGL_RGBA && format != TGL_RGB && format != TGL_BGR && format != TGL_BGRA) || (type != TGL_UNSIGNED_BYTE && type != TGL_UNSIGNED_INT_8_8_8_8_REV)) { error("tglTexImage2D: combination of parameters not handled"); } pixels1 = new byte[c->_textureSize * c->_textureSize * bytes]; if (pixels != NULL) { if (width != c->_textureSize || height != c->_textureSize) { // we use interpolation for better looking result gl_resizeImage(pixels1, c->_textureSize, c->_textureSize, pixels, width, height); width = c->_textureSize; height = c->_textureSize; } else { memcpy(pixels1, pixels, c->_textureSize * c->_textureSize * bytes); } #if defined(SCUMM_BIG_ENDIAN) if (type == TGL_UNSIGNED_INT_8_8_8_8_REV) { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { uint32 offset = (y * width + x) * 4; byte *data = pixels1 + offset; WRITE_BE_UINT32(data, READ_LE_UINT32(data)); } } } #endif } c->current_texture->versionNumber++; im = &c->current_texture->images[level]; im->xsize = width; im->ysize = height; if (im->pixmap) im->pixmap.free(); im->pixmap = Graphics::PixelBuffer(pf, pixels1); if (do_free_after_rgb2rgba) { // pixels as been assigned to tmp.getRawBuffer() which was created with // DisposeAfterUse::NO, therefore delete[] it delete[] pixels; } }
bool BitmapData::loadTile(Common::SeekableReadStream *o) { #ifdef ENABLE_MONKEY4 _x = 0; _y = 0; _format = 1; o->seek(0, SEEK_SET); /*uint32 id = */o->readUint32LE(); // Should check that we actually HAVE a TIL uint32 bmoffset = o->readUint32LE(); _numCoords = o->readUint32LE(); _numLayers = o->readUint32LE(); _numVerts = o->readUint32LE(); // skip some 0 o->seek(16, SEEK_CUR); _texc = new float[_numCoords * 4]; for (uint32 i = 0; i < _numCoords * 4; ++i) { char f[4]; o->read(f, 4); _texc[i] = get_float(f); } _layers = new Layer[_numLayers]; for (uint32 i = 0; i < _numLayers; ++i) { _layers[i]._offset = o->readUint32LE(); _layers[i]._numImages = o->readUint32LE(); } _verts = new Vert[_numVerts]; for (uint32 i = 0; i < _numVerts; ++i) { _verts[i]._texid = o->readUint32LE(); _verts[i]._pos = o->readUint32LE(); _verts[i]._verts = o->readUint32LE(); } o->seek(16, SEEK_CUR); int numSubImages = o->readUint32LE(); char **data = new char *[numSubImages]; o->seek(16, SEEK_CUR); _bpp = o->readUint32LE(); o->seek(bmoffset + 128); _width = o->readUint32LE(); _height = o->readUint32LE(); o->seek(-8, SEEK_CUR); int size = 4 * _width * _height; for (int i = 0; i < numSubImages; ++i) { data[i] = new char[size]; o->seek(8, SEEK_CUR); if (_bpp == 16) { uint32 *d = (uint32 *)data[i]; for (int j = 0; j < _width * _height; ++j) { uint16 p = o->readUint16LE(); // These values are shifted left by 3 so that they saturate the color channel uint8 b = (p & 0x7C00) >> 7; uint8 g = (p & 0x03E0) >> 2; uint8 r = (p & 0x001F) << 3; uint8 a = (p & 0x8000) ? 0xFF : 0x00; // Recombine the color components into a 32 bit RGB value uint32 tmp = (r << 24) | (g << 16) | (b << 8) | a; WRITE_BE_UINT32(&d[j], tmp); } } else if (_bpp == 32) {
static void DumpLong(long i, FILE* D) { byte out[4]; WRITE_BE_UINT32(out, i); DumpBlock(out,4,D); }
void MidiMusicPlayer::playSEQ(uint32 size, bool loop) { // MIDI.DAT holds the file names in DW1 PSX Common::String baseName((char *)g_midiBuffer.pDat, size); Common::String seqName = baseName + ".SEQ"; // TODO: Load the instrument bank (<baseName>.VB and <baseName>.VH) Common::File seqFile; if (!seqFile.open(seqName)) error("Failed to open SEQ file '%s'", seqName.c_str()); if (seqFile.readUint32LE() != MKTAG('S', 'E', 'Q', 'p')) error("Failed to find SEQp tag"); // Make sure we don't have a SEP file (with multiple SEQ's inside) if (seqFile.readUint32BE() != 1) error("Can only play SEQ files, not SEP"); uint16 ppqn = seqFile.readUint16BE(); uint32 tempo = seqFile.readUint16BE() << 8; tempo |= seqFile.readByte(); /* uint16 beat = */ seqFile.readUint16BE(); // SEQ is directly based on SMF and we'll use that to our advantage here // and convert to SMF and then use the SMF MidiParser. // Calculate the SMF size we'll need uint32 dataSize = seqFile.size() - 15; uint32 actualSize = dataSize + 7 + 22; // Resize the buffer if necessary if (g_midiBuffer.size < actualSize) { g_midiBuffer.pDat = (byte *)realloc(g_midiBuffer.pDat, actualSize); assert(g_midiBuffer.pDat); } // Now construct the header WRITE_BE_UINT32(g_midiBuffer.pDat, MKTAG('M', 'T', 'h', 'd')); WRITE_BE_UINT32(g_midiBuffer.pDat + 4, 6); // header size WRITE_BE_UINT16(g_midiBuffer.pDat + 8, 0); // type 0 WRITE_BE_UINT16(g_midiBuffer.pDat + 10, 1); // one track WRITE_BE_UINT16(g_midiBuffer.pDat + 12, ppqn); WRITE_BE_UINT32(g_midiBuffer.pDat + 14, MKTAG('M', 'T', 'r', 'k')); WRITE_BE_UINT32(g_midiBuffer.pDat + 18, dataSize + 7); // SEQ data size + tempo change event size // Add in a fake tempo change event WRITE_BE_UINT32(g_midiBuffer.pDat + 22, 0x00FF5103); // no delta, meta event, tempo change, param size = 3 WRITE_BE_UINT16(g_midiBuffer.pDat + 26, tempo >> 8); g_midiBuffer.pDat[28] = tempo & 0xFF; // Now copy in the rest of the events seqFile.read(g_midiBuffer.pDat + 29, dataSize); seqFile.close(); MidiParser *parser = MidiParser::createParser_SMF(); if (parser->loadMusic(g_midiBuffer.pDat, actualSize)) { parser->setTrack(0); parser->setMidiDriver(this); parser->setTimerRate(getBaseTempo()); parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1); parser->property(MidiParser::mpSendSustainOffOnNotesOff, 1); _parser = parser; _isLooping = loop; _isPlaying = true; } else { delete parser; } }