void MadsM4Engine::dumpFile(const char* filename, bool uncompress) { Common::DumpFile f; byte buffer[DUMP_BUFFER_SIZE]; Common::SeekableReadStream *fileS = res()->get(filename); if (!f.open(filename)) error("Could not open '%s' for writing", filename); int bytesRead = 0; warning("Dumping %s, size: %i\n", filename, fileS->size()); if (!uncompress) { while (!fileS->eos()) { bytesRead = fileS->read(buffer, DUMP_BUFFER_SIZE); f.write(buffer, bytesRead); } } else { MadsPack packData(fileS); Common::SeekableReadStream *sourceUnc; for (int i = 0; i < packData.getCount(); i++) { sourceUnc = packData.getItemStream(i); debugCN(kDebugCore, "Dumping compressed chunk %i of %i, size is %i\n", i + 1, packData.getCount(), sourceUnc->size()); while (!sourceUnc->eos()) { bytesRead = sourceUnc->read(buffer, DUMP_BUFFER_SIZE); f.write(buffer, bytesRead); } delete sourceUnc; } } f.close(); res()->toss(filename); res()->purge(); }
void GagEngine::ExtractCdf(const Common::String &a_fn) { CdfArchive archive(a_fn, true); uint pos = a_fn.size(); for(uint i = 0; i < a_fn.size(); ++i) { if(a_fn[i] == '.') pos = i; } //TODO: figure out how to create directory Common::String dn(ConfMan.get("path") + '/' + Common::String(a_fn.c_str(), pos) + '/'); Common::ArchiveMemberList member_list; archive.listMembers(member_list); for(Common::ArchiveMemberList::iterator it = member_list.begin(); it != member_list.end(); ++it) { Common::ScopedPtr<Common::SeekableReadStream> stream((*it)->createReadStream()); if(stream) { uint8 *buffer = new uint8[stream->size()]; stream->read(buffer, stream->size()); Common::DumpFile file; if(file.open(dn + (*it)->getName())) file.write(buffer, stream->size()); delete [] buffer; } } }
bool Debugger::Cmd_DumpVocab(int argc, const char **argv) { Common::DumpFile outFile; outFile.open("vocab.txt"); for (uint32 i = 0; i < _vm->_game->_scene.getVocabStringsCount(); i++) { Common::String curId = Common::String::format("%x", i + 1); Common::String curVocab = _vm->_game->_scene.getVocab(i + 1); curVocab.toUppercase(); for (uint j = 0; j < curVocab.size(); j++) { if (curVocab[j] == ' ' || curVocab[j] == '-') curVocab.setChar('_', j); } Common::String cur = "\tNOUN_" + curVocab + " = 0x" + curId + ",\n"; outFile.writeString(cur.c_str()); } outFile.flush(); outFile.close(); debugPrintf("Game vocab dumped\n"); return true; }
bool Debugger::cmdDumpFile(int argc, const char **argv) { if (argc != 2) { debugPrintf("Format: dumpfile <resource name>\n"); return true; } Common::SeekableReadStream *s = _vm->_res->load(argv[1]); if (!s) { debugPrintf("Invalid resource.\n"); return true; } byte *buffer = new byte[s->size()]; s->read(buffer, s->size()); Common::DumpFile dumpFile; dumpFile.open(argv[1]); dumpFile.write(buffer, s->size()); dumpFile.flush(); dumpFile.close(); delete[] buffer; debugPrintf("Resource %s has been dumped to disk.\n", argv[1]); return true; }
bool Console::Cmd_DumpFile(int argc, const char **argv) { if (argc != 3) { debugPrintf("Usage: %s <file path> <output file name>\n", argv[0]); return true; } Common::String filePath = argv[1]; Common::String outFileName = argv[2]; BaseFileManager *fileManager = BaseEngine::instance().getFileManager(); Common::SeekableReadStream *inFile = fileManager->openFile(filePath); if (!inFile) { debugPrintf("File '%s' not found\n", argv[1]); return true; } Common::DumpFile *outFile = new Common::DumpFile(); outFile->open(outFileName); byte *data = new byte[inFile->size()]; inFile->read(data, inFile->size()); outFile->write(data, inFile->size()); outFile->finalize(); outFile->close(); delete[] data; delete outFile; delete inFile; debugPrintf("Resource file '%s' dumped to file '%s'\n", argv[1], argv[2]); return true; }
// Dumps all of the game's music in external XMIDI *.xmi files void dumpMusic() { Common::File midiFile; Common::DumpFile outFile; char outName[20]; midiFile.open(MIDI_FILE); int outFileSize = 0; char buffer[20000]; const int total = 155; // maximum (SCN version) for (int i = 0; i < total; i++) { if (midiOffsets[i] == 0) break; sprintf(outName, "track%03d.xmi", i + 1); outFile.open(outName); if (i < total - 1) outFileSize = midiOffsets[i + 1] - midiOffsets[i] - 4; else outFileSize = midiFile.size() - midiOffsets[i] - 4; midiFile.seek(midiOffsets[i] + 4, SEEK_SET); assert(outFileSize < 20000); midiFile.read(buffer, outFileSize); outFile.write(buffer, outFileSize); outFile.close(); } midiFile.close(); }
bool Debugger::Cmd_DumpItems(int argc, const char **argv) { InventoryObjects &objects = _vm->_game->_objects; Common::DumpFile outFile; outFile.open("items.txt"); for (uint32 i = 0; i < objects.size(); i++) { Common::String curId = Common::String::format("%d", i); Common::String desc = _vm->_game->_scene.getVocab(objects[i]._descId); desc.toUppercase(); for (uint j = 0; j < desc.size(); j++) { if (desc[j] == ' ' || desc[j] == '-') desc.setChar('_', j); } Common::String cur = "\tOBJ_" + desc + " = " + curId + ",\n"; outFile.writeString(cur.c_str()); } outFile.flush(); outFile.close(); debugPrintf("Game items dumped\n"); return true; }
bool Debugger::Cmd_DumpFile(int argc, const char **argv) { if (argc != 2) { debugPrintf("Usage: %s <resource>\n", argv[0]); } else { Common::DumpFile outFile; Common::File inFile; if (!inFile.open(argv[1])) { debugPrintf("Specified resource does not exist\n"); } else { outFile.open(argv[1]); byte *data = new byte[inFile.size()]; inFile.read(data, inFile.size()); outFile.write(data, inFile.size()); outFile.flush(); delete[] data; inFile.close(); outFile.close(); debugPrintf("File written successfully.\n"); } } return true; }
bool Node::dumpFaceMask(uint16 index, int face, DirectorySubEntry::ResourceType type) { static const int32 kMaskSize = 640 * 640; byte *mask = new byte[kMaskSize]; memset(mask, 0, kMaskSize); uint32 headerOffset = 0; uint32 dataOffset = 0; const DirectorySubEntry *maskDesc = _vm->getFileDescription(0, index, face, type); if (!maskDesc) { delete[] mask; return false; } Common::MemoryReadStream *maskStream = maskDesc->getData(); while (headerOffset < 400) { int blockX = (headerOffset / sizeof(dataOffset)) % 10; int blockY = (headerOffset / sizeof(dataOffset)) / 10; maskStream->seek(headerOffset, SEEK_SET); dataOffset = maskStream->readUint32LE(); headerOffset = maskStream->pos(); if (dataOffset != 0) { maskStream->seek(dataOffset, SEEK_SET); for(int i = 63; i >= 0; i--) { int x = 0; byte numValues = maskStream->readByte(); for (int j = 0; j < numValues; j++) { byte repeat = maskStream->readByte(); byte value = maskStream->readByte(); for (int k = 0; k < repeat; k++) { mask[((blockY * 64) + i) * 640 + blockX * 64 + x] = value; x++; } } } } } delete maskStream; Common::DumpFile outFile; outFile.open(Common::String::format("dump/%d-%d.masku_%d", index, face, type)); outFile.write(mask, kMaskSize); outFile.close(); delete[] mask; return true; }
void dumpFile(Common::SeekableReadStream *s, const char *outName) { byte *buffer = new byte[s->size()]; s->read(buffer, s->size()); Common::DumpFile dumpFile; dumpFile.open(outName); dumpFile.write(buffer, s->size()); dumpFile.flush(); dumpFile.close(); delete[] buffer; }
bool Debugger::Cmd_DumpFile(int argc, const char **argv) { if (argc < 2) { debugPrintf("Usage: %s <resource> <unpack>\n", argv[0]); debugPrintf(" resource: the resource name\n"); debugPrintf(" unpack: optional, when specified, the FAB/MADSPACK compressed resource is unpacked\n"); } else { Common::DumpFile outFile; Common::File inFile; if (!inFile.open(argv[1])) { debugPrintf("Specified resource does not exist\n"); } else { outFile.open(argv[1]); bool unpack = ((argc >= 3) && !scumm_stricmp(argv[2], "unpack")); byte *data; int totalSize = 0; if (!unpack) { totalSize = inFile.size(); data = new byte[totalSize]; inFile.read(data, totalSize); } else { MadsPack dataPack(&inFile); int count = dataPack.getCount(); for (int i = 0; i < count; i++) { totalSize += dataPack.getItem(i)._size; } data = new byte[totalSize]; byte *ptr = data; for (int i = 0; i < count; i++) { Common::SeekableReadStream *readStream = dataPack.getItemStream(i); readStream->read(ptr, readStream->size()); ptr += readStream->size(); } } outFile.write(data, totalSize); outFile.flush(); delete[] data; inFile.close(); outFile.close(); debugPrintf("File written successfully.\n"); } } return true; }
void tryToDumpLine(const Common::String &key, Common::String &line, Common::HashMap<Common::String, byte> *count, Common::HashMap<Common::String, bool> *fileAlreadyUsed, Common::DumpFile &output) { const byte numberOfExamplesPerType = 8; if ((*count)[key] < numberOfExamplesPerType && !(*fileAlreadyUsed)[key]) { output.writeString(line); output.writeByte('\n'); (*count)[key]++; (*fileAlreadyUsed)[key] = true; } }
void ResMan::dumpRes(uint32 id) { char outn[30]; sprintf(outn, "DUMP%08X.BIN", id); Common::DumpFile outf; if (outf.open(outn)) { resOpen(id); MemHandle *memHandle = resHandle(id); if (memHandle) { outf.write(memHandle->data, memHandle->size); outf.close(); } resClose(id); } }
void ResourceManager::dumpResourcesList(const Common::UString &fileName) const { Common::DumpFile file; if (!file.open(fileName)) throw Common::Exception(Common::kOpenError); file.writeString(" Name | Size \n"); file.writeString("-------------------------------------|-------------\n"); for (ResourceMap::const_iterator itName = _resources.begin(); itName != _resources.end(); ++itName) { for (ResourceTypeMap::const_iterator itType = itName->second.begin(); itType != itName->second.end(); ++itType) { if (itType->second.empty()) continue; const Resource &resource = itType->second.back(); const Common::UString &name = itName->first; const Common::UString ext = setFileType("", resource.type); const uint32 size = getResourceSize(resource); const Common::UString line = Common::UString::sprintf("%32s%4s | %12d\n", name.c_str(), ext.c_str(), size); file.writeString(line); } } file.flush(); if (file.err()) throw Common::Exception("Write error"); file.close(); }
void DirectorySubEntry::dumpToFile(Common::SeekableReadStream &inStream, const char* room, uint32 index) { char fileName[255]; switch (_type) { case kNumMetadata: case kTextMetadata: return; // These types are pure metadata and can't be extracted case kCubeFace: case kSpotItem: case kLocalizedSpotItem: case kFrame: sprintf(fileName, "dump/%s-%d-%d.jpg", room, index, _face); break; case kWaterEffectMask: sprintf(fileName, "dump/%s-%d-%d.mask", room, index, _face); break; case kMovie: case kStillMovie: case kDialogMovie: case kMultitrackMovie: sprintf(fileName, "dump/%s-%d.bik", room, index); break; default: sprintf(fileName, "dump/%s-%d-%d.%d", room, index, _face, _type); break; } debug("Extracted %s", fileName); Common::DumpFile outFile; if (!outFile.open(fileName)) error("Unable to open file '%s' for writing", fileName); inStream.seek(_offset); uint8 *buf = new uint8[_size]; inStream.read(buf, _size); outFile.write(buf, _size); delete[] buf; outFile.close(); }
void ResourceManager::dumpResourcesList(const Common::UString &fileName) const { Common::DumpFile file; if (!file.open(fileName)) throw Common::Exception(Common::kOpenError); file.writeString(" Name | Hash | Size \n"); file.writeString("-------------------------------------|--------------------|-------------\n"); for (ResourceMap::const_iterator r = _resources.begin(); r != _resources.end(); ++r) { if (r->second.empty()) continue; const Resource &res = r->second.back(); const Common::UString &name = res.name; const Common::UString ext = TypeMan.setFileType("", res.type); const uint64 hash = r->first; const uint32 size = getResourceSize(res); const Common::UString line = Common::UString::sprintf("%32s%4s | 0x%016llX | %12d\n", name.c_str(), ext.c_str(), (unsigned long long) hash, size); file.writeString(line); } file.flush(); if (file.err()) throw Common::Exception("Write error"); file.close(); }
void writeFileContentsToFile(const Common::String &sourceFile, const Common::String &destFile) { Common::File f; if (!f.open(sourceFile)) { return; } byte* buffer = new byte[f.size()]; f.read(buffer, f.size()); Common::DumpFile dumpFile; dumpFile.open(destFile); dumpFile.write(buffer, f.size()); dumpFile.flush(); dumpFile.close(); delete[] buffer; }
void ArchiveReader::dump(uint resIndex) { int32 resourceSize = getResourceSize(resIndex); byte *data = new byte[resourceSize]; Common::String fn = Common::String::format("toltecs_res.%03d", resIndex); openResource(resIndex); read(data, resourceSize); closeResource(); Common::DumpFile o; o.open(fn); o.write(data, resourceSize); o.finalize(); o.close(); delete[] data; }
bool Console::Cmd_DumpArchive(int argc, const char **argv) { if (argc != 2) { debugPrintf("Extract all the files from a game archive.\n"); debugPrintf("The destination folder, named 'dump', must exist.\n"); debugPrintf("Usage :\n"); debugPrintf("dumpArchive [archive name]\n"); return true; } Formats::XARCArchive xarc; if (!xarc.open(argv[1])) { debugPrintf("Can't open archive with name '%s'\n", argv[1]); return true; } Common::ArchiveMemberList members; xarc.listMembers(members); for (Common::ArchiveMemberList::const_iterator it = members.begin(); it != members.end(); it++) { Common::String fileName = Common::String::format("dump/%s", it->get()->getName().c_str()); // Open the output file Common::DumpFile outFile; if (!outFile.open(fileName)) { debugPrintf("Unable to open file '%s' for writing\n", fileName.c_str()); return true; } // Copy the archive content to the output file using a temporary buffer Common::SeekableReadStream *inStream = it->get()->createReadStream(); uint8 *buf = new uint8[inStream->size()]; inStream->read(buf, inStream->size()); outFile.write(buf, inStream->size()); delete[] buf; delete inStream; outFile.close(); debugPrintf("Extracted '%s'\n", it->get()->getName().c_str()); } return true; }
bool Console::Cmd_Extract(int argc, const char **argv) { if (argc != 5) { DebugPrintf("Extract a file from the game's archives\n"); DebugPrintf("Usage :\n"); DebugPrintf("extract [room] [node id] [face number] [object type]\n"); return true; } // Room names are uppercase Common::String room = Common::String(argv[1]); room.toUppercase(); uint16 id = atoi(argv[2]); uint16 face = atoi(argv[3]); DirectorySubEntry::ResourceType type = (DirectorySubEntry::ResourceType) atoi(argv[4]); const DirectorySubEntry *desc = _vm->getFileDescription(room.c_str(), id, face, type); if (!desc) { DebugPrintf("File with room %s, id %d, face %d and type %d does not exist\n", room.c_str(), id, face, type); return true; } Common::MemoryReadStream *s = desc->getData(); Common::String filename = Common::String::format("node%s_%d_face%d.%d", room.c_str(), id, face, type); Common::DumpFile f; f.open(filename); uint8 *buf = new uint8[s->size()]; s->read(buf, s->size()); f.write(buf, s->size()); delete[] buf; f.close(); delete s; DebugPrintf("File '%s' successfully written\n", filename.c_str()); return true; }
bool Console::dumpFaceMask(uint16 index, int face, DirectorySubEntry::ResourceType type) { const DirectorySubEntry *maskDesc = _vm->getFileDescription("", index, face, type); if (!maskDesc) return false; Common::MemoryReadStream *maskStream = maskDesc->getData(); Effect::FaceMask *mask = Effect::loadMask(maskStream); delete maskStream; Common::DumpFile outFile; outFile.open(Common::String::format("dump/%d-%d.masku_%d", index, face, type)); outFile.write(mask->surface->getPixels(), mask->surface->pitch * mask->surface->h); outFile.close(); delete mask; return true; }
void dumpBMP(const char *filename, int16 w, int16 h, const byte *bytes, const uint32 *palette) { Common::DumpFile out; byte my_hdr[sizeof(bmp_hdr)]; int i; out.open(filename); if (!out.isOpen()) return; memcpy(my_hdr, bmp_hdr, sizeof(bmp_hdr)); *(uint32 *)(my_hdr + 2) = w * h + 1024 + sizeof(bmp_hdr); *(uint32 *)(my_hdr + 18) = w; *(uint32 *)(my_hdr + 22) = h; out.write(my_hdr, sizeof(my_hdr)); for (i = 0; i != 256; i++, palette++) { byte color[4]; color[0] = (byte)(*palette >> 16); color[1] = (byte)(*palette >> 8); color[2] = (byte)(*palette); color[3] = 0; out.write(color, 4); } while (--h >= 0) { out.write(bytes + h * ((w + 3) & ~3), ((w + 3) & ~3)); } }
void ArchiveReader::dump(uint resIndex, const char *prefix) { int32 resourceSize = getResourceSize(resIndex); byte *data = new byte[resourceSize]; Common::String fn; if (prefix) fn = Common::String::format("%s_%04X.0", prefix, resIndex); else fn = Common::String::format("%04X.0", resIndex); openResource(resIndex); read(data, resourceSize); closeResource(); Common::DumpFile o; o.open(fn); o.write(data, resourceSize); o.finalize(); o.close(); delete[] data; }
void dumpStream(Common::SeekableReadStream &stream, const Common::UString &fileName) { Common::DumpFile file; if (!file.open(fileName)) throw Common::Exception(Common::kOpenError); file.writeStream(stream); file.flush(); if (file.err()) throw Common::Exception(Common::kWriteError); file.close(); }
bool dumpStream(Common::SeekableReadStream &stream, const Common::UString &fileName) { Common::DumpFile file; if (!file.open(fileName)) return false; uint32 pos = stream.pos(); stream.seek(0); file.writeStream(stream); file.flush(); bool error = file.err(); stream.seek(pos); file.close(); return !error; }
void DefaultSaveFileManager::saveTimestamps(Common::HashMap<Common::String, uint32> ×tamps) { Common::DumpFile f; Common::String filename = concatWithSavesPath(TIMESTAMPS_FILENAME); if (!f.open(filename, true)) { warning("DefaultSaveFileManager: failed to open '%s' file to save timestamps", filename.c_str()); return; } for (Common::HashMap<Common::String, uint32>::iterator i = timestamps.begin(); i != timestamps.end(); ++i) { Common::String data = i->_key + Common::String::format(" %u\n", i->_value); if (f.write(data.c_str(), data.size()) != data.size()) { warning("DefaultSaveFileManager: failed to write timestamps data into '%s'", filename.c_str()); return; } } f.flush(); f.finalize(); f.close(); }
bool TwoDAFile::dumpASCII(const Common::UString &fileName) const { Common::DumpFile file; if (!file.open(fileName)) return false; // Write header file.writeString("2DA V2.0\n"); file.writeString(_defaultString); file.writeByte('\n'); // Calculate column lengths std::vector<uint32> colLength; colLength.resize(_headers.size() + 1); const Common::UString maxRow = Common::UString::sprintf("%d", (int)_rows.size() - 1); colLength[0] = maxRow.size(); for (uint32 i = 0; i < _headers.size(); i++) colLength[i + 1] = _headers[i].size(); for (uint32 i = 0; i < _rows.size(); i++) for (uint32 j = 0; j < _rows[i]->_data.size(); j++) colLength[j + 1] = MAX<uint32>(colLength[j + 1], _rows[i]->_data[j].size()); // Write column headers file.writeString(Common::UString::sprintf("%-*s", colLength[0], "")); for (uint32 i = 0; i < _headers.size(); i++) file.writeString(Common::UString::sprintf(" %-*s", colLength[i + 1], _headers[i].c_str())); file.writeByte('\n'); // Write array for (uint32 i = 0; i < _rows.size(); i++) { file.writeString(Common::UString::sprintf("%*d", colLength[0], i)); for (uint32 j = 0; j < _rows[i]->_data.size(); j++) file.writeString(Common::UString::sprintf(" %-*s", colLength[j + 1], _rows[i]->_data[j].c_str())); file.writeByte('\n'); } file.flush(); file.close(); return true; }
bool Console::cmdDumpImage(int argc, const char **argv) { if (argc != 2) { debugPrintf("Use %s <TGA/TGZ name> to dump a Z-Vision TGA/TGZ image into a regular BMP image\n", argv[0]); return true; } Common::String fileName = argv[1]; if (!fileName.hasSuffix(".tga")) { debugPrintf("%s is not an image file", argv[1]); } Common::File f; if (!_engine->getSearchManager()->openFile(f, argv[1])) { warning("File not found: %s", argv[1]); return true; } Graphics::Surface surface; _engine->getRenderManager()->readImageToSurface(argv[1], surface, false); // Open file Common::DumpFile out; fileName.setChar('b', fileName.size() - 3); fileName.setChar('m', fileName.size() - 2); fileName.setChar('p', fileName.size() - 1); out.open(fileName); // Write BMP header out.writeByte('B'); out.writeByte('M'); out.writeUint32LE(surface.h * surface.pitch + 54); out.writeUint32LE(0); out.writeUint32LE(54); out.writeUint32LE(40); out.writeUint32LE(surface.w); out.writeUint32LE(surface.h); out.writeUint16LE(1); out.writeUint16LE(16); out.writeUint32LE(0); out.writeUint32LE(0); out.writeUint32LE(0); out.writeUint32LE(0); out.writeUint32LE(0); out.writeUint32LE(0); // Write pixel data to BMP out.write(surface.getPixels(), surface.pitch * surface.h); out.flush(); out.close(); surface.free(); return true; }
bool Console::cmdRawToWav(int argc, const char **argv) { if (argc != 3) { debugPrintf("Use %s <rawFilePath> <wavFileName> to dump a .RAW file to .WAV\n", argv[0]); return true; } Common::File file; if (!_engine->getSearchManager()->openFile(file, argv[1])) { warning("File not found: %s", argv[1]); return true; } Audio::AudioStream *audioStream = makeRawZorkStream(argv[1], _engine); Common::DumpFile output; output.open(argv[2]); output.writeUint32BE(MKTAG('R', 'I', 'F', 'F')); output.writeUint32LE(file.size() * 2 + 36); output.writeUint32BE(MKTAG('W', 'A', 'V', 'E')); output.writeUint32BE(MKTAG('f', 'm', 't', ' ')); output.writeUint32LE(16); output.writeUint16LE(1); uint16 numChannels; if (audioStream->isStereo()) { numChannels = 2; output.writeUint16LE(2); } else { numChannels = 1; output.writeUint16LE(1); } output.writeUint32LE(audioStream->getRate()); output.writeUint32LE(audioStream->getRate() * numChannels * 2); output.writeUint16LE(numChannels * 2); output.writeUint16LE(16); output.writeUint32BE(MKTAG('d', 'a', 't', 'a')); output.writeUint32LE(file.size() * 2); int16 *buffer = new int16[file.size()]; audioStream->readBuffer(buffer, file.size()); #ifndef SCUMM_LITTLE_ENDIAN for (int i = 0; i < file.size(); ++i) buffer[i] = TO_LE_16(buffer[i]); #endif output.write(buffer, file.size() * 2); delete[] buffer; return true; }
bool BdfFont::cacheFontData(const BdfFont &font, const Common::String &filename) { Common::DumpFile cacheFile; if (!cacheFile.open(filename)) { warning("BdfFont::cacheFontData: Couldn't open file '%s' for writing", filename.c_str()); return false; } const BdfFontData &data = font._data; cacheFile.writeUint32BE(BDF_FONTCACHE_TAG); cacheFile.writeUint32BE(BDF_FONTCACHE_VERSION); cacheFile.writeUint16BE(data.maxAdvance); cacheFile.writeByte(data.height); cacheFile.writeByte(data.defaultBox.width); cacheFile.writeByte(data.defaultBox.height); cacheFile.writeSByte(data.defaultBox.xOffset); cacheFile.writeSByte(data.defaultBox.yOffset); cacheFile.writeByte(data.ascent); cacheFile.writeUint16BE(data.firstCharacter); cacheFile.writeSint16BE(data.defaultCharacter); cacheFile.writeUint16BE(data.numCharacters); for (int i = 0; i < data.numCharacters; ++i) { const BdfBoundingBox &box = data.boxes ? data.boxes[i] : data.defaultBox; if (data.bitmaps[i]) { const int bytes = ((box.width + 7) / 8) * box.height; cacheFile.writeUint32BE(bytes); cacheFile.write(data.bitmaps[i], bytes); } else { cacheFile.writeUint32BE(0); } } if (data.advances) { cacheFile.writeByte(0xFF); cacheFile.write(data.advances, data.numCharacters); } else { cacheFile.writeByte(0x00); } if (data.boxes) { cacheFile.writeByte(0xFF); for (int i = 0; i < data.numCharacters; ++i) { const BdfBoundingBox &box = data.boxes[i]; cacheFile.writeByte(box.width); cacheFile.writeByte(box.height); cacheFile.writeSByte(box.xOffset); cacheFile.writeSByte(box.yOffset); } } else { cacheFile.writeByte(0x00); } return !cacheFile.err(); }