From d8319ef4a9610f2c893b364ad65cb2be3c4fc459 Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Sat, 3 Mar 2012 11:27:26 +0200 Subject: [PATCH] Lua Bitmap WIP --- include/lua/bitmap.hpp | 41 +++++++ manual.lyx | 223 ++++++++++++++++++++++++++++++++++++++ manual.txt | 128 ++++++++++++++++++++-- src/lua/gui-bitmap.cpp | 283 +++++++++++++++++++++++++++++++++++++++++++++++++ src/lua/loadbitmap.cpp | 80 ++++++++++++++ 5 files changed, 748 insertions(+), 7 deletions(-) create mode 100644 include/lua/bitmap.hpp create mode 100644 src/lua/gui-bitmap.cpp create mode 100644 src/lua/loadbitmap.cpp diff --git a/include/lua/bitmap.hpp b/include/lua/bitmap.hpp new file mode 100644 index 00000000..4ae965ba --- /dev/null +++ b/include/lua/bitmap.hpp @@ -0,0 +1,41 @@ +#ifndef _lua__bitmap__hpp__included__ +#define _lua__bitmap__hpp__included__ + +#include +#include +#include +#include "core/render.hpp" + +struct lua_bitmap +{ + lua_bitmap(uint32_t w, uint32_t h); + size_t width; + size_t height; + std::vector pixels; +}; + +struct lua_dbitmap +{ + lua_dbitmap(uint32_t w, uint32_t h); + size_t width; + size_t height; + std::vector pixels; +}; + +struct lua_palette +{ + std::vector colors; +}; + +struct lua_loaded_bitmap +{ + size_t w; + size_t h; + bool d; + std::vector bitmap; + std::vector palette; + static struct lua_loaded_bitmap load(const std::string& name); +}; + + +#endif diff --git a/manual.lyx b/manual.lyx index 78d66cef..69608ad6 100644 --- a/manual.lyx +++ b/manual.lyx @@ -2347,6 +2347,229 @@ fill: Fill color (default is -1 (transparent)). \end_layout \begin_layout Subsubsection +gui.bitmap_draw(number x, number y, bitmap bitmap, palette palette) +\end_layout + +\begin_layout Standard +Draw a bitmap on screen with specified palette. + Parameters: +\end_layout + +\begin_layout Itemize +x: X-coordinate of left edge. +\end_layout + +\begin_layout Itemize +y: Y-coordinate of top edge. +\end_layout + +\begin_layout Itemize +bitmap: The bitmap to draw +\end_layout + +\begin_layout Itemize +palette: The palette to draw the bitmap using. +\end_layout + +\begin_layout Subsubsection +gui.bitmap_draw(number x, number y, dbitmap bitmap) +\end_layout + +\begin_layout Standard +Draw a bitmap on screen. + Parameters: +\end_layout + +\begin_layout Itemize +x: X-coordinate of left edge. +\end_layout + +\begin_layout Itemize +y: Y-coordinate of top edge. +\end_layout + +\begin_layout Itemize +bitmap: The bitmap to draw +\end_layout + +\begin_layout Subsubsection +gui.palette_new() +\end_layout + +\begin_layout Standard +Returns a new palette (initially all transparent). + Can be used anywhere. +\end_layout + +\begin_layout Subsubsection +gui.bitmap_new(number w, number h, boolean direct) +\end_layout + +\begin_layout Standard +Returns a new bitmap/dbitmap. + Can be used anywhere. + Parameters: +\end_layout + +\begin_layout Itemize +w: The width of new bitmap +\end_layout + +\begin_layout Itemize +h: The height of new bitmap +\end_layout + +\begin_layout Itemize +direct: If true, the returned bitmap is dbitmap, otherwise bitmap. +\end_layout + +\begin_layout Subsubsection +gui.bitmap_load(string file) +\end_layout + +\begin_layout Standard +Returns loaded bitmap/dbitmap (if bitmap, the second return value is palette + for bitmap). + Can be used anywhere. + Parameters: +\end_layout + +\begin_layout Itemize +file: The name of file to load. +\end_layout + +\begin_layout Subsubsection +gui.palette_set(palette palette, number index, number color) +\end_layout + +\begin_layout Standard +Sets color in palette. + Can be used anywhere. + Parameters: +\end_layout + +\begin_layout Itemize +palette: The palette to manipulate +\end_layout + +\begin_layout Itemize +index: Index of color (0-65535). +\end_layout + +\begin_layout Itemize +color: The color value. +\end_layout + +\begin_layout Subsubsection +gui.bitmap_pset(bitmap/dbitmap bitmap, number x, number y, number color) +\end_layout + +\begin_layout Standard +Sets specified pixel in bitmap. + Can be used anywhere. + Parameters: +\end_layout + +\begin_layout Itemize +bitmap: The bitmap to manipulate +\end_layout + +\begin_layout Itemize +x: The x-coordinate of the pixel. +\end_layout + +\begin_layout Itemize +y: The y-coordinate of the pixel. +\end_layout + +\begin_layout Itemize +color: If bitmap is a bitmap, color index (0-65535). + Otherwise color value. +\end_layout + +\begin_layout Subsubsection +gui.bitmap_size(bitmap/dbitmap bitmap) +\end_layout + +\begin_layout Standard +Get size of bitmap. + Can be used anywhere. + Parameters: +\end_layout + +\begin_layout Itemize +bitmap: The bitmap to query. +\end_layout + +\begin_layout Standard +The first return is the width, the second is the height. +\end_layout + +\begin_layout Subsubsection +gui.bitmap_blit(bitmap/dbitmap dest, number dx, number dy, bitmap/dbitmap + src, number sx, number sy, number w, number h[, number ck]) +\end_layout + +\begin_layout Standard +Blit a part of bitmap to another. + Can be used anywhere. + Parameters: +\end_layout + +\begin_layout Itemize +dest: Destination to blit to. +\end_layout + +\begin_layout Itemize +dx: left edge of target +\end_layout + +\begin_layout Itemize +dy: Top edge of target +\end_layout + +\begin_layout Itemize +src: The source to blit from. + Must be of the same type as destination. +\end_layout + +\begin_layout Itemize +sx: left edge of source +\end_layout + +\begin_layout Itemize +sy: Top edge of source +\end_layout + +\begin_layout Itemize +w: Width of region +\end_layout + +\begin_layout Itemize +h: Height of region. +\end_layout + +\begin_layout Itemize +ck: Color key. + Pixels of this color are not blitted. +\end_layout + +\begin_deeper +\begin_layout Itemize +If bitmaps are bitmaps, this is color index of colorkey. + Values outside range 0-65535 cause no key to be used as colorkey. +\end_layout + +\begin_layout Itemize +If bitmaps are dbitmaps, this color value of colorkey. +\end_layout + +\begin_layout Itemize +May be absent or nil for no colorkey blit. +\end_layout + +\end_deeper +\begin_layout Subsubsection gui.repaint() \end_layout diff --git a/manual.txt b/manual.txt index 716ae3a9..e7a464ef 100644 --- a/manual.txt +++ b/manual.txt @@ -1150,29 +1150,142 @@ Draw a circle. Parameters. • fill: Fill color (default is -1 (transparent)). -8.3.12 gui.repaint() +8.3.12 gui.bitmap_draw(number x, number y, bitmap bitmap, palette + palette) + +Draw a bitmap on screen with specified palette. Parameters: + +• x: X-coordinate of left edge. + +• y: Y-coordinate of top edge. + +• bitmap: The bitmap to draw + +• palette: The palette to draw the bitmap using. + +8.3.13 gui.bitmap_draw(number x, number y, dbitmap bitmap) + +Draw a bitmap on screen. Parameters: + +• x: X-coordinate of left edge. + +• y: Y-coordinate of top edge. + +• bitmap: The bitmap to draw + +8.3.14 gui.palette_new() + +Returns a new palette (initially all transparent). Can be used +anywhere. + +8.3.15 gui.bitmap_new(number w, number h, boolean direct) + +Returns a new bitmap/dbitmap. Can be used anywhere. Parameters: + +• w: The width of new bitmap + +• h: The height of new bitmap + +• direct: If true, the returned bitmap is dbitmap, otherwise + bitmap. + +8.3.16 gui.bitmap_load(string file) + +Returns loaded bitmap/dbitmap (if bitmap, the second return value +is palette for bitmap). Can be used anywhere. Parameters: + +• file: The name of file to load. + +8.3.17 gui.palette_set(palette palette, number index, number + color) + +Sets color in palette. Can be used anywhere. Parameters: + +• palette: The palette to manipulate + +• index: Index of color (0-65535). + +• color: The color value. + +8.3.18 gui.bitmap_pset(bitmap/dbitmap bitmap, number x, number y, + number color) + +Sets specified pixel in bitmap. Can be used anywhere. Parameters: + +• bitmap: The bitmap to manipulate + +• x: The x-coordinate of the pixel. + +• y: The y-coordinate of the pixel. + +• color: If bitmap is a bitmap, color index (0-65535). Otherwise + color value. + +8.3.19 gui.bitmap_size(bitmap/dbitmap bitmap) + +Get size of bitmap. Can be used anywhere. Parameters: + +• bitmap: The bitmap to query. + +The first return is the width, the second is the height. + +8.3.20 gui.bitmap_blit(bitmap/dbitmap dest, number dx, number dy, + bitmap/dbitmap src, number sx, number sy, number w, number h[, + number ck]) + +Blit a part of bitmap to another. Can be used anywhere. +Parameters: + +• dest: Destination to blit to. + +• dx: left edge of target + +• dy: Top edge of target + +• src: The source to blit from. Must be of the same type as + destination. + +• sx: left edge of source + +• sy: Top edge of source + +• w: Width of region + +• h: Height of region. + +• ck: Color key. Pixels of this color are not blitted. + + – If bitmaps are bitmaps, this is color index of colorkey. + Values outside range 0-65535 cause no key to be used as + colorkey. + + – If bitmaps are dbitmaps, this color value of colorkey. + + – May be absent or nil for no colorkey blit. + +8.3.21 gui.repaint() Request on_repaint() to happen as soon as possible. Can be used anywhere. -8.3.13 gui.subframe_update(boolean on) +8.3.22 gui.subframe_update(boolean on) Request subframe updates (calling on_paint() on subframes) to happen (on=true) or not happen (on=false). Can be used anywhere. -8.3.14 gui.screenshot(string filename) +8.3.23 gui.screenshot(string filename) Write PNG screenshot of the current frame (no drawings) to specified file. Can be used anywhere. -8.3.15 gui.color(number r, number g, number b[, number a]) +8.3.24 gui.color(number r, number g, number b[, number a]) Returns color (in notation Lua scripts use) corresponding to color (r,g,b), each component in scale 0-255. If a is specified, that is alpha (0 is fully transparent, 256(sic) is fully opaque). The default alpha is 256. -8.3.16 gui.status(string name, string value) +8.3.25 gui.status(string name, string value) Set status field “L[]” to in status area. Can be used anywhere. @@ -2662,7 +2775,8 @@ set-axis joystick0axis19 disabled • Try to autodetect if ROM is headered. -• Only bring up ROM patching screen if specifically requested. +• Wxwidgets: Only bring up ROM patching screen if specifically + requested. -• Allow configuring some (200+) hotkeys. +• Allow configuring some hotkeys. diff --git a/src/lua/gui-bitmap.cpp b/src/lua/gui-bitmap.cpp new file mode 100644 index 00000000..c85a22c5 --- /dev/null +++ b/src/lua/gui-bitmap.cpp @@ -0,0 +1,283 @@ +#include "core/lua-int.hpp" +#include "core/render.hpp" +#include "lua/bitmap.hpp" +#include + +lua_bitmap::lua_bitmap(uint32_t w, uint32_t h) +{ + width = w; + height = h; + pixels.resize(width * height); + memset(&pixels[0], 0, width * height); +} + +lua_dbitmap::lua_dbitmap(uint32_t w, uint32_t h) +{ + width = w; + height = h; + pixels.resize(width * height); +} + +namespace +{ + struct render_object_bitmap : public render_object + { + render_object_bitmap(int32_t _x, int32_t _y, lua_obj_pin* _bitmap, + lua_obj_pin* _palette) throw() + { + x = _x; + y = _y; + b = _bitmap; + b2 = NULL; + p = _palette; + } + + render_object_bitmap(int32_t _x, int32_t _y, lua_obj_pin* _bitmap) throw() + { + x = _x; + y = _y; + b = NULL; + b2 = _bitmap; + p = NULL; + } + + ~render_object_bitmap() throw() + { + delete b; + delete b2; + delete p; + } + + void operator()(struct screen& scr) throw() + { + size_t pallim = 0; + size_t w, h; + premultiplied_color* palette; + if(b) { + palette = &p->object()->colors[0]; + for(auto& c : p->object()->colors) + c.set_palette(scr); + pallim = p->object()->colors.size(); + w = b->object()->width; + h = b->object()->height; + } else { + for(auto& c : b2->object()->pixels) + c.set_palette(scr); + w = b2->object()->width; + h = b2->object()->height; + } + + int32_t xmin = 0; + int32_t xmax = w; + int32_t ymin = 0; + int32_t ymax = h; + clip_range(scr.originx, scr.width, x, xmin, xmax); + clip_range(scr.originy, scr.height, y, ymin, ymax); + for(int32_t r = ymin; r < ymax; r++) { + uint32_t* rptr = scr.rowptr(y + r + scr.originy); + size_t eptr = x + xmin + scr.originx; + if(b) + for(int32_t c = xmin; c < xmax; c++, eptr++) { + uint16_t i = b->object()->pixels[r * b->object()->width + c]; + if(i < pallim) + palette[i].apply(rptr[eptr]); + } + else + for(int32_t c = xmin; c < xmax; c++, eptr++) + b2->object()->pixels[r * b2->object()->width + c].apply(rptr[eptr]); + } + } + private: + int32_t x; + int32_t y; + lua_obj_pin* b; + lua_obj_pin* b2; + lua_obj_pin* p; + }; + + function_ptr_luafun gui_bitmap("gui.bitmap_draw", [](lua_State* LS, const std::string& fname) -> int { + if(!lua_render_ctx) + return 0; + int32_t x = get_numeric_argument(LS, 1, fname.c_str()); + int32_t y = get_numeric_argument(LS, 2, fname.c_str()); + if(lua_class::is(LS, 3)) { + lua_class::get(LS, 3, fname.c_str()); + lua_class::get(LS, 4, fname.c_str()); + auto b = lua_class::pin(LS, 3, fname.c_str()); + auto p = lua_class::pin(LS, 4, fname.c_str()); + lua_render_ctx->queue->add(*new render_object_bitmap(x, y, b, p)); + } else if(lua_class::is(LS, 3)) { + lua_class::get(LS, 3, fname.c_str()); + auto b = lua_class::pin(LS, 3, fname.c_str()); + lua_render_ctx->queue->add(*new render_object_bitmap(x, y, b)); + } else { + lua_pushstring(LS, "Expected BITMAP or DBITMAP as argument 3 for gui.bitmap_draw."); + lua_error(LS); + } + return 0; + }); + + function_ptr_luafun gui_cpalette("gui.palette_new", [](lua_State* LS, const std::string& fname) -> int { + lua_class::create(LS); + return 1; + }); + + function_ptr_luafun gui_cbitmap("gui.bitmap_new", [](lua_State* LS, const std::string& fname) -> int { + uint32_t w = get_numeric_argument(LS, 1, fname.c_str()); + uint32_t h = get_numeric_argument(LS, 2, fname.c_str()); + bool d = get_boolean_argument(LS, 3, fname.c_str()); + if(d) + lua_class::create(LS, w, h); + else + lua_class::create(LS, w, h); + return 1; + }); + + function_ptr_luafun gui_epalette("gui.palette_set", [](lua_State* LS, const std::string& fname) -> int { + lua_palette* p = lua_class::get(LS, 1, fname.c_str()); + uint16_t c = get_numeric_argument(LS, 2, fname.c_str()); + int64_t nval = get_numeric_argument(LS, 3, fname.c_str()); + premultiplied_color nc(nval); + if(p->colors.size() <= c); + p->colors.resize(static_cast(c) + 1); + p->colors[c] = nc; + return 0; + }); + + function_ptr_luafun pset_bitmap("gui.bitmap_pset", [](lua_State* LS, const std::string& fname) -> int { + uint32_t x = get_numeric_argument(LS, 2, fname.c_str()); + uint32_t y = get_numeric_argument(LS, 3, fname.c_str()); + if(lua_class::is(LS, 1)) { + lua_bitmap* b = lua_class::get(LS, 1, fname.c_str()); + uint16_t c = get_numeric_argument(LS, 4, fname.c_str()); + if(x >= b->width || y >= b->height) + return 0; + b->pixels[y * b->width + x] = c; + } else if(lua_class::is(LS, 1)) { + lua_dbitmap* b = lua_class::get(LS, 1, fname.c_str()); + int64_t c = get_numeric_argument(LS, 4, fname.c_str()); + if(x >= b->width || y >= b->height) + return 0; + b->pixels[y * b->width + x] = premultiplied_color(c); + } else { + lua_pushstring(LS, "Expected BITMAP or DBITMAP as argument 1 for gui.bitmap_pset."); + lua_error(LS); + } + return 0; + }); + + function_ptr_luafun size_bitmap("gui.bitmap_size", [](lua_State* LS, const std::string& fname) -> int { + if(lua_class::is(LS, 1)) { + lua_bitmap* b = lua_class::get(LS, 1, fname.c_str()); + lua_pushnumber(LS, b->width); + lua_pushnumber(LS, b->height); + } else if(lua_class::is(LS, 1)) { + lua_dbitmap* b = lua_class::get(LS, 1, fname.c_str()); + lua_pushnumber(LS, b->width); + lua_pushnumber(LS, b->height); + } else { + lua_pushstring(LS, "Expected BITMAP or DBITMAP as argument 1 for gui.bitmap_size."); + lua_error(LS); + } + return 2; + }); + + function_ptr_luafun blit_bitmap("gui.bitmap_blit", [](lua_State* LS, const std::string& fname) -> int { + uint32_t dx = get_numeric_argument(LS, 2, fname.c_str()); + uint32_t dy = get_numeric_argument(LS, 3, fname.c_str()); + uint32_t sx = get_numeric_argument(LS, 5, fname.c_str()); + uint32_t sy = get_numeric_argument(LS, 6, fname.c_str()); + uint32_t w = get_numeric_argument(LS, 7, fname.c_str()); + uint32_t h = get_numeric_argument(LS, 8, fname.c_str()); + int64_t ck = 0x100000000ULL; + get_numeric_argument(LS, 9, ck, fname.c_str()); + bool nck = false; + premultiplied_color pck(ck); + uint32_t ckorig = pck.orig; + uint16_t ckoriga = pck.origa; + if(ck == 0x100000000ULL) + nck = true; + if(lua_class::is(LS, 1) && lua_class::is(LS, 4)) { + lua_bitmap* db = lua_class::get(LS, 1, fname.c_str()); + lua_bitmap* sb = lua_class::get(LS, 4, fname.c_str()); + while((dx + w > db->width || sx + w > sb->width) && w > 0) + w--; + while((dy + h > db->height || sy + h > sb->height) && h > 0) + h--; + size_t sidx = sy * sb->width + sx; + size_t didx = dy * db->width + dx; + size_t srskip = sb->width - w; + size_t drskip = db->width - w; + for(uint32_t j = 0; j < h; j++) { + for(uint32_t i = 0; i < w; i++) { + uint16_t pix = sb->pixels[sidx]; + if(pix != ck) //No need to check nck, as that value is out of range. + db->pixels[didx] = pix; + sidx++; + didx++; + } + sidx += srskip; + didx += drskip; + } + } else if(lua_class::is(LS, 1) && lua_class::is(LS, 1)) { + lua_dbitmap* db = lua_class::get(LS, 1, fname.c_str()); + lua_dbitmap* sb = lua_class::get(LS, 4, fname.c_str()); + while((dx + w > db->width || sx + w > sb->width) && w > 0) + w--; + while((dy + h > db->height || sy + h > sb->height) && h > 0) + h--; + size_t sidx = sy * sb->width + sx; + size_t didx = dy * db->width + dx; + size_t srskip = sb->width - w; + size_t drskip = db->width - w; + for(uint32_t j = 0; j < h; j++) { + for(uint32_t i = 0; i < w; i++) { + premultiplied_color pix = sb->pixels[sidx]; + if(pix.orig != ckorig || pix.origa != ckoriga || nck) + db->pixels[didx] = pix; + sidx++; + didx++; + } + sidx += srskip; + didx += drskip; + } + } else { + lua_pushstring(LS, "Expected BITMAP or DBITMAP as arguments 1&4 for gui.bitmap_pset."); + lua_error(LS); + } + return 0; + }); + + function_ptr_luafun gui_loadbitmap("gui.bitmap_load", [](lua_State* LS, const std::string& fname) -> int { + std::string name = get_string_argument(LS, 1, fname.c_str()); + uint32_t w, h; + auto bitmap = lua_loaded_bitmap::load(name); + if(bitmap.d) { + lua_dbitmap* b = lua_class::create(LS, bitmap.w, bitmap.h); + for(size_t i = 0; i < bitmap.w * bitmap.h; i++) + b->pixels[i] = premultiplied_color(bitmap.bitmap[i]); + return 1; + } else { + lua_bitmap* b = lua_class::create(LS, bitmap.w, bitmap.h); + lua_palette* p = lua_class::create(LS); + for(size_t i = 0; i < bitmap.w * bitmap.h; i++) + b->pixels[i] = bitmap.bitmap[i]; + p->colors.resize(bitmap.palette.size()); + for(size_t i = 0; i < bitmap.palette.size(); i++) + p->colors[i] = premultiplied_color(bitmap.palette[i]); + return 2; + } + }); + + function_ptr_luafun gui_dpalette("gui.palette_debug", [](lua_State* LS, const std::string& fname) -> int { + lua_palette* p = lua_class::get(LS, 1, fname.c_str()); + size_t i = 0; + for(auto c : p->colors) + messages << "Color #" << (i++) << ": " << c.orig << ":" << c.origa << std::endl; + return 0; + }); +} + +DECLARE_LUACLASS(lua_palette, "PALETTE"); +DECLARE_LUACLASS(lua_bitmap, "BITMAP"); +DECLARE_LUACLASS(lua_dbitmap, "DBITMAP"); diff --git a/src/lua/loadbitmap.cpp b/src/lua/loadbitmap.cpp new file mode 100644 index 00000000..35713f48 --- /dev/null +++ b/src/lua/loadbitmap.cpp @@ -0,0 +1,80 @@ +#include "lua/bitmap.hpp" +#include "library/zip.hpp" +#include + +namespace +{ + inline uint64_t tocolor(unsigned r, unsigned g, unsigned b, unsigned a) + { + if(!a) + return -1; + else + return (static_cast(256 - a) << 24) | (static_cast(r) << 16) | + (static_cast(g) << 8) | static_cast(b); + } +} + +struct lua_loaded_bitmap lua_loaded_bitmap::load(const std::string& name) +{ + struct lua_loaded_bitmap b; + std::istream* file = NULL; + try { + std::string magic; + unsigned pcolors; + unsigned R; + unsigned G; + unsigned B; + unsigned A; + file = &open_file_relative(name, ""); + *file >> magic; + if(magic != "LSNES-BITMAP") + throw std::runtime_error("Bitmap load: Wrong magic"); + *file >> b.w; + *file >> b.h; + if(b.h >= std::numeric_limits::max() / b.w) + throw std::runtime_error("Bitmap load: Bitmap too large"); + b.bitmap.resize(b.w * b.h); + *file >> pcolors; + if(pcolors > 65536) + throw std::runtime_error("Bitmap load: Palette too big"); + if(pcolors > 0) { + //Paletted. + b.d = false; + b.palette.resize(pcolors); + for(size_t i = 0; i < pcolors; i++) { + *file >> R; + *file >> G; + *file >> B; + *file >> A; + if(R > 255 || G > 255 || B > 255 || A > 256) //Yes, a can be 256. + throw std::runtime_error("Bitmap load: Palette entry out of range"); + b.palette[i] = tocolor(R, G, B, A); + } + for(size_t i = 0; i < b.w * b.h; i++) { + *file >> R; + if(R >= pcolors) + throw std::runtime_error("Bitmap load: color index out of range"); + b.bitmap[i] = R; + } + } else { + //Direct. + b.d = true; + for(size_t i = 0; i < b.w * b.h; i++) { + *file >> R; + *file >> G; + *file >> B; + *file >> A; + if(R > 255 || G > 255 || B > 255 || A > 256) //Yes, a can be 256. + throw std::runtime_error("Bitmap load: Color out of range"); + b.bitmap[i] = tocolor(R, G, B, A); + } + } + if(!*file) + throw std::runtime_error("Bitmap load: Error reading bitmap"); + } catch(...) { + delete file; + throw; + } + delete file; + return b; +} -- 2.11.4.GIT