static bool Bitmap_getTiffImageSize(StackBuffer<256> &data, const io::Producer &file, size_t &width, size_t &height) { auto reader = Reader(data.data() + 4, 4); auto offset = reader.readUnsigned32(); data.clear(); if (file.seekAndRead(offset, data, 2) != 2) { return false; } auto size = Reader(data.data(), 2).readUnsigned16(); auto dictSize = size * 12; offset += 2; while (dictSize > 0) { data.clear(); size_t blockSize = min(12 * 21, dictSize); if (file.read(data, blockSize) != blockSize) { return false; } auto blocks = blockSize / 12; reader = Reader(data.data(), blockSize); for (uint16_t i = 0; i < blocks; ++i) { auto tagid = reader.readUnsigned16(); auto type = reader.readUnsigned16(); auto count = reader.readUnsigned32(); if (tagid == 256 && count == 1) { if (type == 3) { width = reader.readUnsigned16(); reader.offset(2); } else if (type == 4) { width = reader.readUnsigned32(); } else { reader.offset(4); } } else if (tagid == 257 && count == 1) { if (type == 3) { height = reader.readUnsigned16(); reader.offset(2); } else if (type == 4) { height = reader.readUnsigned32(); } else { reader.offset(4); } return true; } else { if (tagid > 257) { return false; } reader.offset(4); } } } return false; }
bool Bitmap::getImageSize(const io::Producer &file, size_t &width, size_t &height) { StackBuffer<256> data; if (file.seekAndRead(0, data, 30) < 30) { return false; } if (isPng(data.data(), data.size()) && data.size() >= 24) { auto reader = DataReader<ByteOrder::Network>(data.data() + 16, 8); width = reader.readUnsigned32(); height = reader.readUnsigned32(); return true; } else if(isJpg(data.data(), data.size())) { size_t offset = 2; uint16_t len = 0; uint8_t marker = 0; auto reader = DataReader<ByteOrder::Network>(data.data() + 2, data.size() - 2); while (reader.is((uint8_t)0xFF)) { ++ reader; } marker = reader.readUnsigned(); len = reader.readUnsigned16(); while (marker < 0xC0 || marker > 0xCF) { offset += 2 + len; data.clear(); if (file.seekAndRead(offset, data, 12) != 12) { return false; } if (data.size() >= 12) { reader = data.get<DataReader<ByteOrder::Network>>(); while (reader.is((uint8_t)0xFF)) { ++ reader; } marker = reader.readUnsigned(); len = reader.readUnsigned16(); } else { reader.clear(); break; } } if (reader >= 5 && marker >= 0xC0 && marker <= 0xCF) { ++ reader; height = reader.readUnsigned16(); width = reader.readUnsigned16(); return true; } return false; } else if (isGif(data.data(), data.size())) { auto reader = DataReader<ByteOrder::Little>(data.data() + 6, 4); width = reader.readUnsigned16(); height = reader.readUnsigned16(); return true; } else if (isWebp(data.data(), data.size())) { auto reader = DataReader<ByteOrder::Little>(data.data() + 26, 4); width = reader.readUnsigned16(); height = reader.readUnsigned16(); return true; } else if (isTiff(data.data(), data.size())) { if (memcmp(data.data(), "II", 2) == 0) { if (Bitmap_getTiffImageSize<DataReader<ByteOrder::Little>>(data, file, width, height)) { return true; } } else { if (Bitmap_getTiffImageSize<DataReader<ByteOrder::Big>>(data, file, width, height)) { return true; } } } return false; }
void initFileObject(lua_State* L) { luaL_newmetatable(L, meta<File>()); // Duplicate the metatable on the stack. lua_pushvalue(L, -1); // metatable.__index = metatable lua_setfield(L, -2, "__index"); // Put the members into the metatable. const luaL_Reg functions[] = { {"__gc", [](lua_State* L) { return script::wrapped<File>(L, 1)->gc(L); }}, {"__index", [](lua_State* L) { return script::wrapped<File>(L, 1)->index(L); }}, {"__newindex", [](lua_State* L) { return script::wrapped<File>(L, 1)->newindex(L); }}, {"__tostring", [](lua_State* L) { return script::wrapped<File>(L, 1)->tostring(L); }}, {"__pairs", [](lua_State* L) { return script::wrapped<File>(L, 1)->pairs(L); }}, {"close", [](lua_State* L) { auto file = script::ptr<File>(L, 1); file->close(); return 0; }}, {"readUnsigned8", [](lua_State* L) { auto file = script::ptr<File>(L, 1); uint8_t value; if(file->readUnsigned8(value)) { script::push(L, value); return 1; } return 0; }}, {"readUnsigned16", [](lua_State* L) { auto file = script::ptr<File>(L, 1); uint16_t value; if(file->readUnsigned16(value)) { script::push(L, value); return 1; } return 0; }}, {"readUnsigned32", [](lua_State* L) { auto file = script::ptr<File>(L, 1); uint32_t value; if(file->readUnsigned32(value)) { script::push(L, value); return 1; } return 0; }}, {"readInt8", [](lua_State* L) { auto file = script::ptr<File>(L, 1); int8_t value; if(file->readInt8(value)) { script::push(L, value); return 1; } return 0; }}, {"readInt16", [](lua_State* L) { auto file = script::ptr<File>(L, 1); int16_t value; if(file->readInt16(value)) { script::push(L, value); return 1; } return 0; }}, {"readInt32", [](lua_State* L) { auto file = script::ptr<File>(L, 1); int32_t value; if(file->readInt32(value)) { script::push(L, value); return 1; } return 0; }}, {"readFloat", [](lua_State* L) { auto file = script::ptr<File>(L, 1); float value; if(file->readFloat(value)) { script::push(L, value); return 1; } return 0; }}, {"readDouble", [](lua_State* L) { auto file = script::ptr<File>(L, 1); double value; if(file->readDouble(value)) { script::push(L, value); return 1; } return 0; }}, {"readString", [](lua_State* L) { auto file = script::ptr<File>(L, 1); auto blockSize = script::get<int>(L, 2); std::string buffer(blockSize, 0); if(file->readString(buffer)) { lua_pushlstring(L, buffer.data(), buffer.size()); return 1; } return 0; }}, {"readLine", [](lua_State* L) { auto file = script::ptr<File>(L, 1); std::string value; if(file->readLine(value)) { script::push(L, value.c_str()); return 1; } return 0; }}, {"readFully", [](lua_State* L) { auto file = script::ptr<File>(L, 1); // Get current position. auto pos = file->tell(); if(pos == -1) { return 0; } // Length to read = position of end - current. auto length = 0; if(!file->seek(pos, FileSeekMode::End)) { return 0; } length = file->tell() - pos; if(!file->seek(pos, FileSeekMode::Start)) { return 0; } // Read the entire file into a string. std::string buf(length, 0); if(file->readString(buf)) { lua_pushlstring(L, buf.data(), buf.size()); return 1; } return 0; }}, {"writeUnsigned8", [](lua_State* L) { auto file = script::ptr<File>(L, 1); auto value = script::get<int>(L, 2); script::push(L, file->writeUnsigned8(value)); return 1; }}, {"writeUnsigned16", [](lua_State* L) { auto file = script::ptr<File>(L, 1); auto value = script::get<int>(L, 2); script::push(L, file->writeUnsigned16(value)); return 1; }}, {"writeUnsigned32", [](lua_State* L) { auto file = script::ptr<File>(L, 1); auto value = script::get<int>(L, 2); script::push(L, file->writeUnsigned32(value)); return 1; }}, {"writeInt8", [](lua_State* L) { auto file = script::ptr<File>(L, 1); auto value = script::get<int>(L, 2); script::push(L, file->writeInt8(value)); return 1; }}, {"writeInt16", [](lua_State* L) { auto file = script::ptr<File>(L, 1); auto value = script::get<int>(L, 2); script::push(L, file->writeInt16(value)); return 1; }}, {"writeInt32", [](lua_State* L) { auto file = script::ptr<File>(L, 1); auto value = script::get<int>(L, 2); script::push(L, file->writeInt32(value)); return 1; }}, {"writeFloat", [](lua_State* L) { auto file = script::ptr<File>(L, 1); auto value = script::get<double>(L, 2); script::push(L, file->writeFloat((float) value)); return 1; }}, {"writeDouble", [](lua_State* L) { auto file = script::ptr<File>(L, 1); auto value = script::get<double>(L, 2); script::push(L, file->writeDouble(value)); return 1; }}, {"writeString", [](lua_State* L) { auto file = script::ptr<File>(L, 1); size_t length = 0; const char* buffer = luaL_checklstring(L, 2, &length); std::string value(buffer, buffer + length); script::push(L, file->writeString(value)); return 1; }}, {"writeLine", [](lua_State* L) { auto file = script::ptr<File>(L, 1); size_t length = 0; const char* buffer = luaL_checklstring(L, 2, &length); std::string value(buffer, buffer + length); script::push(L, file->writeLine(value)); return 1; }}, {"tell", [](lua_State* L) { auto file = script::ptr<File>(L, 1); script::push(L, int(file->tell())); return 1; }}, {"seek", [](lua_State* L) { auto file = script::ptr<File>(L, 1); auto position = script::get<int>(L, 2); auto mode = FileSeekMode(script::get<int>(L, 3)); script::push(L, file->seek(position, mode)); return 1; }}, {"flush", [](lua_State* L) { auto file = script::ptr<File>(L, 1); file->flush(); return 0; }}, {nullptr, nullptr}, }; luaL_setfuncs(L, functions, 0); lua_pop(L, 1); // Push plum namespace. lua_getglobal(L, "plum"); // plum.File = <function create> script::push(L, "File"); lua_pushcfunction(L, [](lua_State* L) { auto filename = script::get<const char*>(L, 1); auto mode = FileOpenMode(script::get<int>(L, 2)); auto f = new File(filename, mode); // Failure. if(!f->isActive()) { delete f; return 0; } script::push(L, f, LUA_NOREF); return 1; }); lua_settable(L, -3); // Pop plum namespace. lua_pop(L, 1); }