Refactor core APIs, fix bugs, and improve safety
- Make image result/info structs readonly; improve error handling and memory safety in image library - Introduce IJobScheduler interface; move job scheduling docs to interface - Remove "index 0 invalid" convention from slot/sparse maps; fix Count logic - Add Owner<T> for disposable value types in low-level utilities - Improve ObjectPool<T> thread safety and logic - Change List<T>.RemoveAndSwapBack to return bool - Remove unsafe methods from generated math types; add debug range checks - Update benchmarks and enable collection checks in tests - Improve documentation, comments, and error messages - Bump assembly versions across all projects
This commit is contained in:
@@ -25,7 +25,9 @@ namespace Misaki.HighPerformance.Image
|
||||
*x = g.w;
|
||||
*y = g.h;
|
||||
if (req_comp != 0 && req_comp != 4)
|
||||
{
|
||||
u = stbi__convert_format(u, 4, req_comp, (uint)g.w, (uint)g.h);
|
||||
}
|
||||
}
|
||||
else if (g._out_ != null)
|
||||
{
|
||||
@@ -51,7 +53,10 @@ namespace Misaki.HighPerformance.Image
|
||||
var out_size = 0;
|
||||
var delays_size = 0;
|
||||
if (delays != null)
|
||||
{
|
||||
*delays = null;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
u = stbi__gif_load_next(s, g, comp, req_comp, two_back);
|
||||
@@ -65,14 +70,20 @@ namespace Misaki.HighPerformance.Image
|
||||
{
|
||||
void* tmp = (byte*)CRuntime.realloc(_out_, (ulong)(layers * stride));
|
||||
if (tmp == null)
|
||||
{
|
||||
return stbi__load_gif_main_outofmem(g, _out_, delays);
|
||||
}
|
||||
|
||||
_out_ = (byte*)tmp;
|
||||
out_size = layers * stride;
|
||||
if (delays != null)
|
||||
{
|
||||
var new_delays = (int*)CRuntime.realloc(*delays, (ulong)(sizeof(int) * layers));
|
||||
if (new_delays == null)
|
||||
{
|
||||
return stbi__load_gif_main_outofmem(g, _out_, delays);
|
||||
}
|
||||
|
||||
*delays = new_delays;
|
||||
delays_size = layers * sizeof(int);
|
||||
}
|
||||
@@ -81,22 +92,33 @@ namespace Misaki.HighPerformance.Image
|
||||
{
|
||||
_out_ = (byte*)stbi__malloc((ulong)(layers * stride));
|
||||
if (_out_ == null)
|
||||
{
|
||||
return stbi__load_gif_main_outofmem(g, _out_, delays);
|
||||
}
|
||||
|
||||
out_size = layers * stride;
|
||||
if (delays != null)
|
||||
{
|
||||
*delays = (int*)stbi__malloc((ulong)(layers * sizeof(int)));
|
||||
if (*delays == null)
|
||||
{
|
||||
return stbi__load_gif_main_outofmem(g, _out_, delays);
|
||||
}
|
||||
|
||||
delays_size = layers * sizeof(int);
|
||||
}
|
||||
}
|
||||
|
||||
CRuntime.memcpy(_out_ + (layers - 1) * stride, u, (ulong)stride);
|
||||
if (layers >= 2)
|
||||
{
|
||||
two_back = _out_ - 2 * stride;
|
||||
}
|
||||
|
||||
if (delays != null)
|
||||
{
|
||||
(*delays)[layers - 1U] = g.delay;
|
||||
}
|
||||
}
|
||||
} while (u != null);
|
||||
|
||||
@@ -104,7 +126,10 @@ namespace Misaki.HighPerformance.Image
|
||||
CRuntime.free(g.history);
|
||||
CRuntime.free(g.background);
|
||||
if (req_comp != 0 && req_comp != 4)
|
||||
{
|
||||
_out_ = stbi__convert_format(_out_, 4, req_comp, (uint)(layers * g.w), (uint)g.h);
|
||||
}
|
||||
|
||||
*z = layers;
|
||||
return _out_;
|
||||
}
|
||||
@@ -121,12 +146,21 @@ namespace Misaki.HighPerformance.Image
|
||||
{
|
||||
var sz = 0;
|
||||
if (stbi__get8(s) != 71 || stbi__get8(s) != 73 || stbi__get8(s) != 70 || stbi__get8(s) != 56)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
sz = stbi__get8(s);
|
||||
if (sz != 57 && sz != 55)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stbi__get8(s) != 97)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -146,12 +180,21 @@ namespace Misaki.HighPerformance.Image
|
||||
{
|
||||
byte version = 0;
|
||||
if (stbi__get8(s) != 71 || stbi__get8(s) != 73 || stbi__get8(s) != 70 || stbi__get8(s) != 56)
|
||||
{
|
||||
return stbi__err("not GIF");
|
||||
}
|
||||
|
||||
version = stbi__get8(s);
|
||||
if (version != 55 && version != 57)
|
||||
{
|
||||
return stbi__err("not GIF");
|
||||
}
|
||||
|
||||
if (stbi__get8(s) != 97)
|
||||
{
|
||||
return stbi__err("not GIF");
|
||||
}
|
||||
|
||||
stbi__g_failure_reason = "";
|
||||
g.w = stbi__get16le(s);
|
||||
g.h = stbi__get16le(s);
|
||||
@@ -160,15 +203,30 @@ namespace Misaki.HighPerformance.Image
|
||||
g.ratio = stbi__get8(s);
|
||||
g.transparent = -1;
|
||||
if (g.w > 1 << 24)
|
||||
{
|
||||
return stbi__err("too large");
|
||||
}
|
||||
|
||||
if (g.h > 1 << 24)
|
||||
{
|
||||
return stbi__err("too large");
|
||||
}
|
||||
|
||||
if (comp != null)
|
||||
{
|
||||
*comp = 4;
|
||||
}
|
||||
|
||||
if (is_info != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((g.flags & 0x80) != 0)
|
||||
{
|
||||
stbi__gif_parse_colortable(s, g.pal, 2 << (g.flags & 7), -1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -176,7 +234,10 @@ namespace Misaki.HighPerformance.Image
|
||||
{
|
||||
var g = new stbi__gif();
|
||||
if (g == null)
|
||||
{
|
||||
return stbi__err("outofmem");
|
||||
}
|
||||
|
||||
if (stbi__gif_header(s, g, comp, 1) == 0)
|
||||
{
|
||||
stbi__rewind(s);
|
||||
@@ -184,9 +245,15 @@ namespace Misaki.HighPerformance.Image
|
||||
}
|
||||
|
||||
if (x != null)
|
||||
{
|
||||
*x = g.w;
|
||||
}
|
||||
|
||||
if (y != null)
|
||||
{
|
||||
*y = g.h;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -195,9 +262,15 @@ namespace Misaki.HighPerformance.Image
|
||||
byte* p;
|
||||
var idx = 0;
|
||||
if (g.codes[code].prefix >= 0)
|
||||
{
|
||||
stbi__out_gif_code(g, (ushort)g.codes[code].prefix);
|
||||
}
|
||||
|
||||
if (g.cur_y >= g.max_y)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
idx = g.cur_x + g.cur_y;
|
||||
p = &g._out_[idx];
|
||||
g.history[idx / 4] = 1;
|
||||
@@ -240,7 +313,10 @@ namespace Misaki.HighPerformance.Image
|
||||
stbi__gif_lzw* p;
|
||||
lzw_cs = stbi__get8(s);
|
||||
if (lzw_cs > 12)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
clear = 1 << lzw_cs;
|
||||
first = 1;
|
||||
codesize = lzw_cs + 1;
|
||||
@@ -258,13 +334,16 @@ namespace Misaki.HighPerformance.Image
|
||||
oldcode = -1;
|
||||
len = 0;
|
||||
for (; ; )
|
||||
{
|
||||
if (valid_bits < codesize)
|
||||
{
|
||||
if (len == 0)
|
||||
{
|
||||
len = stbi__get8(s);
|
||||
if (len == 0)
|
||||
{
|
||||
return g._out_;
|
||||
}
|
||||
}
|
||||
|
||||
--len;
|
||||
@@ -288,20 +367,29 @@ namespace Misaki.HighPerformance.Image
|
||||
{
|
||||
stbi__skip(s, len);
|
||||
while ((len = stbi__get8(s)) > 0)
|
||||
{
|
||||
stbi__skip(s, len);
|
||||
}
|
||||
|
||||
return g._out_;
|
||||
}
|
||||
else if (code <= avail)
|
||||
{
|
||||
if (first != 0)
|
||||
{
|
||||
return (byte*)(ulong)(stbi__err("no clear code") != 0 ? 0 : 0);
|
||||
}
|
||||
|
||||
if (oldcode >= 0)
|
||||
{
|
||||
fixed (stbi__gif_lzw* p2 = &g.codes[avail++])
|
||||
{
|
||||
p = p2;
|
||||
if (avail > 8192)
|
||||
{
|
||||
return (byte*)(ulong)(stbi__err("too many codes") != 0 ? 0 : 0);
|
||||
}
|
||||
|
||||
p->prefix = (short)oldcode;
|
||||
p->first = g.codes[oldcode].first;
|
||||
p->suffix = code == avail ? p->first : g.codes[code].first;
|
||||
@@ -326,6 +414,7 @@ namespace Misaki.HighPerformance.Image
|
||||
return (byte*)(ulong)(stbi__err("illegal code in raster") != 0 ? 0 : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static byte* stbi__gif_load_next(stbi__context s, stbi__gif g, int* comp, int req_comp, byte* two_back)
|
||||
@@ -338,15 +427,24 @@ namespace Misaki.HighPerformance.Image
|
||||
if (g._out_ == null)
|
||||
{
|
||||
if (stbi__gif_header(s, g, comp, 0) == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (stbi__mad3sizes_valid(4, g.w, g.h, 0) == 0)
|
||||
{
|
||||
return (byte*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
||||
}
|
||||
|
||||
pcount = g.w * g.h;
|
||||
g._out_ = (byte*)stbi__malloc((ulong)(4 * pcount));
|
||||
g.background = (byte*)stbi__malloc((ulong)(4 * pcount));
|
||||
g.history = (byte*)stbi__malloc((ulong)pcount);
|
||||
if (g._out_ == null || g.background == null || g.history == null)
|
||||
{
|
||||
return (byte*)(ulong)(stbi__err("outofmem") != 0 ? 0 : 0);
|
||||
}
|
||||
|
||||
CRuntime.memset(g._out_, 0x00, (ulong)(4 * pcount));
|
||||
CRuntime.memset(g.background, 0x00, (ulong)(4 * pcount));
|
||||
CRuntime.memset(g.history, 0x00, (ulong)pcount);
|
||||
@@ -357,18 +455,29 @@ namespace Misaki.HighPerformance.Image
|
||||
dispose = (g.eflags & 0x1C) >> 2;
|
||||
pcount = g.w * g.h;
|
||||
if (dispose == 3 && two_back == null)
|
||||
{
|
||||
dispose = 2;
|
||||
}
|
||||
|
||||
if (dispose == 3)
|
||||
{
|
||||
for (pi = 0; pi < pcount; ++pi)
|
||||
{
|
||||
if (g.history[pi] != 0)
|
||||
{
|
||||
CRuntime.memcpy(&g._out_[pi * 4], &two_back[pi * 4], (ulong)4);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (dispose == 2)
|
||||
{
|
||||
for (pi = 0; pi < pcount; ++pi)
|
||||
{
|
||||
if (g.history[pi] != 0)
|
||||
{
|
||||
CRuntime.memcpy(&g._out_[pi * 4], &g.background[pi * 4], (ulong)4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CRuntime.memcpy(g.background, g._out_, (ulong)(4 * g.w * g.h));
|
||||
@@ -392,7 +501,10 @@ namespace Misaki.HighPerformance.Image
|
||||
w = stbi__get16le(s);
|
||||
h = stbi__get16le(s);
|
||||
if (x + w > g.w || y + h > g.h)
|
||||
{
|
||||
return (byte*)(ulong)(stbi__err("bad Image Descriptor") != 0 ? 0 : 0);
|
||||
}
|
||||
|
||||
g.line_size = g.w * 4;
|
||||
g.start_x = x * 4;
|
||||
g.start_y = y * g.line_size;
|
||||
@@ -401,7 +513,10 @@ namespace Misaki.HighPerformance.Image
|
||||
g.cur_x = g.start_x;
|
||||
g.cur_y = g.start_y;
|
||||
if (w == 0)
|
||||
{
|
||||
g.cur_y = g.max_y;
|
||||
}
|
||||
|
||||
g.lflags = stbi__get8(s);
|
||||
if ((g.lflags & 0x40) != 0)
|
||||
{
|
||||
@@ -431,10 +546,15 @@ namespace Misaki.HighPerformance.Image
|
||||
|
||||
o = stbi__process_gif_raster(s, g);
|
||||
if (o == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
pcount = g.w * g.h;
|
||||
if (first_frame != 0 && g.bgindex > 0)
|
||||
{
|
||||
for (pi = 0; pi < pcount; ++pi)
|
||||
{
|
||||
if (g.history[pi] == 0)
|
||||
{
|
||||
g.pal[g.bgindex][3] = 255;
|
||||
@@ -443,6 +563,8 @@ namespace Misaki.HighPerformance.Image
|
||||
CRuntime.memcpy(&g._out_[pi * 4], ptr, (ulong)4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
@@ -459,12 +581,17 @@ namespace Misaki.HighPerformance.Image
|
||||
g.eflags = stbi__get8(s);
|
||||
g.delay = 10 * stbi__get16le(s);
|
||||
if (g.transparent >= 0)
|
||||
{
|
||||
g.pal[g.transparent][3] = 255;
|
||||
}
|
||||
|
||||
if ((g.eflags & 0x01) != 0)
|
||||
{
|
||||
g.transparent = stbi__get8(s);
|
||||
if (g.transparent >= 0)
|
||||
{
|
||||
g.pal[g.transparent][3] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -480,7 +607,10 @@ namespace Misaki.HighPerformance.Image
|
||||
}
|
||||
|
||||
while ((len = stbi__get8(s)) != 0)
|
||||
{
|
||||
stbi__skip(s, len);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -498,9 +628,15 @@ namespace Misaki.HighPerformance.Image
|
||||
CRuntime.free(g.history);
|
||||
CRuntime.free(g.background);
|
||||
if (_out_ != null)
|
||||
{
|
||||
CRuntime.free(_out_);
|
||||
}
|
||||
|
||||
if (delays != null && *delays != null)
|
||||
{
|
||||
CRuntime.free(*delays);
|
||||
}
|
||||
|
||||
return (byte*)(ulong)(stbi__err("outofmem") != 0 ? 0 : 0);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user