Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
itdan3344
stb
提交
50479cb0
S
stb
项目概览
itdan3344
/
stb
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
S
stb
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
50479cb0
编写于
3月 26, 2016
作者:
S
Sean Barrett
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
stb_image: allow jpegs that are rgb not YCrCb
上级
8aa9afb3
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
869 addition
and
3 deletion
+869
-3
stb_image.h
stb_image.h
+20
-3
tests/stb.dsw
tests/stb.dsw
+12
-0
tools/unicode.c
tools/unicode.c
+749
-0
tools/unicode/unicode.dsp
tools/unicode/unicode.dsp
+88
-0
未找到文件。
stb_image.h
浏览文件 @
50479cb0
...
...
@@ -1506,6 +1506,7 @@ typedef struct
int
succ_high
;
int
succ_low
;
int
eob_run
;
int
rgb
;
int
scan_n
,
order
[
4
];
int
restart_interval
,
todo
;
...
...
@@ -2717,11 +2718,17 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan)
if
(
Lf
!=
8
+
3
*
s
->
img_n
)
return
stbi__err
(
"bad SOF len"
,
"Corrupt JPEG"
);
z
->
rgb
=
0
;
for
(
i
=
0
;
i
<
s
->
img_n
;
++
i
)
{
static
unsigned
char
rgb
[
3
]
=
{
'R'
,
'G'
,
'B'
};
z
->
img_comp
[
i
].
id
=
stbi__get8
(
s
);
if
(
z
->
img_comp
[
i
].
id
!=
i
+
1
)
// JFIF requires
if
(
z
->
img_comp
[
i
].
id
!=
i
)
// some version of jpegtran outputs non-JFIF-compliant files!
return
stbi__err
(
"bad component ID"
,
"Corrupt JPEG"
);
if
(
z
->
img_comp
[
i
].
id
!=
i
)
{
// some version of jpegtran outputs non-JFIF-compliant files!
// somethings output this (see http://fileformats.archiveteam.org/wiki/JPEG#Color_format)
if
(
z
->
img_comp
[
i
].
id
!=
rgb
[
i
])
return
stbi__err
(
"bad component ID"
,
"Corrupt JPEG"
);
++
z
->
rgb
;
}
q
=
stbi__get8
(
s
);
z
->
img_comp
[
i
].
h
=
(
q
>>
4
);
if
(
!
z
->
img_comp
[
i
].
h
||
z
->
img_comp
[
i
].
h
>
4
)
return
stbi__err
(
"bad H"
,
"Corrupt JPEG"
);
z
->
img_comp
[
i
].
v
=
q
&
15
;
if
(
!
z
->
img_comp
[
i
].
v
||
z
->
img_comp
[
i
].
v
>
4
)
return
stbi__err
(
"bad V"
,
"Corrupt JPEG"
);
...
...
@@ -3383,7 +3390,17 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp
if
(
n
>=
3
)
{
stbi_uc
*
y
=
coutput
[
0
];
if
(
z
->
s
->
img_n
==
3
)
{
z
->
YCbCr_to_RGB_kernel
(
out
,
y
,
coutput
[
1
],
coutput
[
2
],
z
->
s
->
img_x
,
n
);
if
(
z
->
rgb
==
3
)
{
for
(
i
=
0
;
i
<
z
->
s
->
img_x
;
++
i
)
{
out
[
0
]
=
y
[
i
];
out
[
1
]
=
coutput
[
1
][
i
];
out
[
2
]
=
coutput
[
2
][
i
];
out
[
3
]
=
255
;
out
+=
n
;
}
}
else
{
z
->
YCbCr_to_RGB_kernel
(
out
,
y
,
coutput
[
1
],
coutput
[
2
],
z
->
s
->
img_x
,
n
);
}
}
else
for
(
i
=
0
;
i
<
z
->
s
->
img_x
;
++
i
)
{
out
[
0
]
=
out
[
1
]
=
out
[
2
]
=
y
[
i
];
...
...
tests/stb.dsw
浏览文件 @
50479cb0
...
...
@@ -123,6 +123,18 @@ Package=<4>
###############################################################################
Project: "unicode"=..\tools\unicode\unicode.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "vorbseek"=.\vorbseek\vorbseek.dsp - Package Owner=<4>
Package=<5>
...
...
tools/unicode.c
0 → 100644
浏览文件 @
50479cb0
#define STB_DEFINE
#include "../stb.h"
// create unicode mappings
//
// Two kinds of mappings:
// map to a number
// map to a bit
//
// For mapping to a number, we use the following strategy:
//
// User supplies:
// 1. a table of numbers (for now we use uint16, so full Unicode table is 4MB)
// 2. a "don't care" value
// 3. define a 'fallback' value (typically 0)
// 4. define a fast-path range (typically 0..255 or 0..1023) [@TODO: automate detecting this]
//
// Code:
// 1. Determine range of *end* of unicode codepoints (U+10FFFF and down) which
// all have the same value (or don't care). If large enough, emit this as a
// special case in the code.
// 2. Repeat above, limited to at most U+FFFF.
// 3. Cluster the data into intervals of 8,16,32,64,128,256 numeric values.
// 3a. If all the values in an interval are fallback/dont-care, no further processing
// 3b. Find the "trimmed range" outside which all the values are the fallback or don't care
// 3c. Find the "special trimmed range" outside which all the values are some constant or don't care
// 4. Pack the clusters into continuous memory, and find previous instances of
// the cluster. Repeat for trimmed & special-trimmed. In the first case, find
// previous instances of the cluster (allow don't-care to match in either
// direction), both aligned and mis-aligned; in the latter, starting where
// things start or mis-aligned. Build an index table specifiying the
// location of each cluster (and its length). Allow an extra indirection here;
// the full-sized index can index a smaller table which has the actual offset
// (and lengths).
// 5. Associate with each packed continuous memory above the amount of memory
// required to store the data w/ smallest datatype (of uint8, uint16, uint32).
// Discard the continuous memory. Recurse on each index table, but avoid the
// smaller packing.
//
// For mapping to a bit, we pack the results for 8 characters into a byte, and then apply
// the above strategy. Note that there may be more optimal approaches with e.g. packing
// 8 different bits into a single structure, though, which we should explore eventually.
// currently we limit *indices* to being 2^16, and we pack them as
// index + end_trim*2^16 + start_trim*2^24; specials have to go in a separate table
typedef
uint32
uval
;
#define UVAL_DONT_CARE_DEFAULT 0xffffffff
typedef
struct
{
uval
*
input
;
uint32
dont_care
;
uint32
fallback
;
int
fastpath
;
int
length
;
int
depth
;
int
has_sign
;
int
splittable
;
int
replace_fallback_with_codepoint
;
size_t
input_size
;
size_t
inherited_storage
;
}
table
;
typedef
struct
{
int
split_log2
;
table
result
;
// index into not-returned table
int
storage
;
}
output
;
typedef
struct
{
table
t
;
char
**
output_name
;
}
info
;
typedef
struct
{
size_t
path
;
size_t
size
;
}
result
;
typedef
struct
{
uint8
trim_end
;
uint8
trim_start
;
uint8
special
;
uint8
aligned
;
uint8
indirect
;
uint16
overhead
;
// add some forced overhead for each mode to avoid getting complex encoding when it doesn't save much
}
mode_info
;
mode_info
modes
[]
=
{
{
0
,
0
,
0
,
0
,
0
,
32
,
},
{
0
,
0
,
0
,
0
,
1
,
100
,
},
{
0
,
0
,
0
,
1
,
0
,
32
,
},
{
0
,
0
,
0
,
1
,
1
,
100
,
},
{
0
,
0
,
1
,
0
,
1
,
100
,
},
{
0
,
0
,
1
,
1
,
0
,
32
,
},
{
0
,
0
,
1
,
1
,
1
,
200
,
},
{
1
,
0
,
0
,
0
,
0
,
100
,
},
{
1
,
0
,
0
,
0
,
1
,
120
,
},
{
1
,
1
,
0
,
0
,
0
,
100
,
},
{
1
,
1
,
0
,
0
,
1
,
130
,
},
{
1
,
0
,
1
,
0
,
0
,
130
,
},
{
1
,
0
,
1
,
0
,
1
,
180
,
},
{
1
,
1
,
1
,
0
,
0
,
180
,
},
{
1
,
1
,
1
,
0
,
1
,
200
,
},
};
#define MODECOUNT (sizeof(modes)/sizeof(modes[0]))
#define CLUSTERSIZECOUNT 6 // 8,16, 32,64, 128,256
size_t
size_for_max_number
(
uint32
number
)
{
if
(
number
==
0
)
return
0
;
if
(
number
<
256
)
return
1
;
if
(
number
<
256
*
256
)
return
2
;
if
(
number
<
256
*
256
*
256
)
return
3
;
return
4
;
}
size_t
size_for_max_number_aligned
(
uint32
number
)
{
size_t
n
=
size_for_max_number
(
number
);
return
n
==
3
?
4
:
n
;
}
uval
get_data
(
uval
*
data
,
int
offset
,
uval
*
end
)
{
if
(
data
+
offset
>=
end
)
return
0
;
else
return
data
[
offset
];
}
int
safe_len
(
uval
*
data
,
int
len
,
uval
*
end
)
{
if
(
len
>
end
-
data
)
return
end
-
data
;
return
len
;
}
uval
tempdata
[
256
];
int
dirty
=
0
;
size_t
find_packed
(
uval
**
packed
,
uval
*
data
,
int
len
,
int
aligned
,
int
fastpath
,
uval
*
end
,
int
offset
,
int
replace
)
{
int
packlen
=
stb_arr_len
(
*
packed
);
int
i
,
p
;
if
(
data
+
len
>
end
||
replace
)
{
int
safelen
=
safe_len
(
data
,
len
,
end
);
memset
(
tempdata
,
0
,
dirty
*
sizeof
(
tempdata
[
0
]));
memcpy
(
tempdata
,
data
,
safelen
*
sizeof
(
data
[
0
]));
data
=
tempdata
;
dirty
=
len
;
}
if
(
replace
)
{
int
i
;
int
safelen
=
safe_len
(
data
,
len
,
end
);
for
(
i
=
0
;
i
<
safelen
;
++
i
)
if
(
data
[
i
]
==
0
)
data
[
i
]
=
offset
+
i
;
}
if
(
len
<=
0
)
return
0
;
if
(
!
fastpath
)
{
if
(
aligned
)
{
for
(
i
=
0
;
i
<
packlen
;
i
+=
len
)
if
((
*
packed
)[
i
]
==
data
[
0
]
&&
0
==
memcmp
(
&
(
*
packed
)[
i
],
data
,
len
*
sizeof
(
uval
)))
return
i
/
len
;
}
else
{
for
(
i
=
0
;
i
<
packlen
-
len
+
1
;
i
+=
1
)
if
((
*
packed
)[
i
]
==
data
[
0
]
&&
0
==
memcmp
(
&
(
*
packed
)[
i
],
data
,
len
*
sizeof
(
uval
)))
return
i
;
}
}
p
=
stb_arr_len
(
*
packed
);
for
(
i
=
0
;
i
<
len
;
++
i
)
stb_arr_push
(
*
packed
,
data
[
i
]);
return
p
;
}
void
output_table
(
char
*
name1
,
char
*
name2
,
uval
*
data
,
int
length
,
int
sign
,
char
**
names
)
{
char
temp
[
20
];
uval
maxv
=
0
;
int
bytes
,
numlen
,
at_newline
;
int
linelen
=
79
;
// @TODO: make table more readable by choosing a length that's a multiple?
int
i
,
pos
,
do_split
=
0
;
for
(
i
=
0
;
i
<
length
;
++
i
)
if
(
sign
)
maxv
=
stb_max
(
maxv
,
(
uval
)
abs
((
int
)
data
[
i
]));
else
maxv
=
stb_max
(
maxv
,
data
[
i
]);
bytes
=
size_for_max_number_aligned
(
maxv
);
sprintf
(
temp
,
"%d"
,
maxv
);
numlen
=
strlen
(
temp
);
if
(
sign
)
++
numlen
;
if
(
bytes
==
0
)
return
;
printf
(
"uint%d %s%s[%d] = {
\n
"
,
bytes
*
8
,
name1
,
name2
,
length
);
at_newline
=
1
;
for
(
i
=
0
;
i
<
length
;
++
i
)
{
if
(
pos
+
numlen
+
2
>
linelen
)
{
printf
(
"
\n
"
);
at_newline
=
1
;
pos
=
0
;
}
if
(
at_newline
)
{
printf
(
" "
);
pos
=
2
;
at_newline
=
0
;
}
else
{
printf
(
" "
);
++
pos
;
}
printf
(
"%*d,"
,
numlen
,
data
[
i
]);
pos
+=
numlen
+
1
;
}
if
(
!
at_newline
)
printf
(
"
\n
"
);
printf
(
"};
\n
"
);
}
void
output_table_with_trims
(
char
*
name1
,
char
*
name2
,
uval
*
data
,
int
length
)
{
uval
maxt
=
0
,
maxp
=
0
;
int
i
,
d
,
s
,
e
,
count
;
// split the table into two pieces
uval
*
trims
=
NULL
;
if
(
length
==
0
)
return
;
for
(
i
=
0
;
i
<
stb_arr_len
(
data
);
++
i
)
{
stb_arr_push
(
trims
,
data
[
i
]
>>
16
);
data
[
i
]
&=
0xffff
;
maxt
=
stb_max
(
maxt
,
trims
[
i
]);
maxp
=
stb_max
(
maxp
,
data
[
i
]);
}
d
=
s
=
e
=
1
;
if
(
maxt
>=
256
)
{
// need to output start & end values
if
(
maxp
>=
256
)
{
// can pack into a single table
printf
(
"struct { uint16 val; uint8 start, end; } %s%s[%d] = {
\n
"
,
name1
,
name2
,
length
);
}
else
{
output_table
(
name1
,
name2
,
data
,
length
,
0
,
0
);
d
=
0
;
printf
(
"struct { uint8 start, end; } %s%s_trim[%d] = {
\n
"
,
name1
,
name2
,
length
);
}
}
else
if
(
maxt
>
0
)
{
if
(
maxp
>=
256
)
{
output_table
(
name1
,
name2
,
data
,
length
,
0
,
0
);
output_table
(
name1
,
stb_sprintf
(
"%s_end"
,
name2
),
trims
,
length
,
0
,
0
);
return
;
}
else
{
printf
(
"struct { uint8 val, end; } %s%s[%d] = {
\n
"
,
name1
,
name2
,
length
);
s
=
0
;
}
}
else
{
output_table
(
name1
,
name2
,
data
,
length
,
0
,
0
);
return
;
}
// d or s can be zero (but not both), e is always present and last
count
=
d
+
s
+
e
;
assert
(
count
>=
2
&&
count
<=
3
);
{
char
temp
[
60
];
uval
maxv
=
0
;
int
numlen
,
at_newline
,
len
;
int
linelen
=
79
;
// @TODO: make table more readable by choosing a length that's a multiple?
int
i
,
pos
,
do_split
=
0
;
numlen
=
0
;
for
(
i
=
0
;
i
<
length
;
++
i
)
{
if
(
count
==
2
)
sprintf
(
temp
,
"{%d,%d}"
,
d
?
data
[
i
]
:
(
trims
[
i
]
>>
8
),
trims
[
i
]
&
255
);
else
sprintf
(
temp
,
"{%d,%d,%d}"
,
data
[
i
],
trims
[
i
]
>>
8
,
trims
[
i
]
&
255
);
len
=
strlen
(
temp
);
numlen
=
stb_max
(
len
,
numlen
);
}
at_newline
=
1
;
for
(
i
=
0
;
i
<
length
;
++
i
)
{
if
(
pos
+
numlen
+
2
>
linelen
)
{
printf
(
"
\n
"
);
at_newline
=
1
;
pos
=
0
;
}
if
(
at_newline
)
{
printf
(
" "
);
pos
=
2
;
at_newline
=
0
;
}
else
{
printf
(
" "
);
++
pos
;
}
if
(
count
==
2
)
sprintf
(
temp
,
"{%d,%d}"
,
d
?
data
[
i
]
:
(
trims
[
i
]
>>
8
),
trims
[
i
]
&
255
);
else
sprintf
(
temp
,
"{%d,%d,%d}"
,
data
[
i
],
trims
[
i
]
>>
8
,
trims
[
i
]
&
255
);
printf
(
"%*s,"
,
numlen
,
temp
);
pos
+=
numlen
+
1
;
}
if
(
!
at_newline
)
printf
(
"
\n
"
);
printf
(
"};
\n
"
);
}
}
int
weight
=
1
;
table
pack_for_mode
(
table
*
t
,
int
mode
,
char
*
table_name
)
{
size_t
extra_size
;
int
i
;
uval
maxv
;
mode_info
mi
=
modes
[
mode
%
MODECOUNT
];
int
size
=
8
<<
(
mode
/
MODECOUNT
);
table
newtab
;
uval
*
packed
=
NULL
;
uval
*
index
=
NULL
;
uval
*
indirect
=
NULL
;
uval
*
specials
=
NULL
;
newtab
.
dont_care
=
UVAL_DONT_CARE_DEFAULT
;
if
(
table_name
)
printf
(
"// clusters of %d
\n
"
,
size
);
for
(
i
=
0
;
i
<
t
->
length
;
i
+=
size
)
{
uval
newval
;
int
fastpath
=
(
i
<
t
->
fastpath
);
if
(
mi
.
special
)
{
int
end_trim
=
size
-
1
;
int
start_trim
=
0
;
uval
special
;
// @TODO: pick special from start or end instead of only end depending on which is longer
for
(;;)
{
special
=
t
->
input
[
i
+
end_trim
];
if
(
special
!=
t
->
dont_care
||
end_trim
==
0
)
break
;
--
end_trim
;
}
// at this point, special==inp[end_trim], and end_trim >= 0
if
(
special
==
t
->
dont_care
&&
!
fastpath
)
{
// entire block is don't care, so OUTPUT don't care
stb_arr_push
(
index
,
newtab
.
dont_care
);
continue
;
}
else
{
uval
pos
,
trim
;
if
(
mi
.
trim_end
&&
!
fastpath
)
{
while
(
end_trim
>=
0
)
{
if
(
t
->
input
[
i
+
end_trim
]
==
special
||
t
->
input
[
i
+
end_trim
]
==
t
->
dont_care
)
--
end_trim
;
else
break
;
}
}
if
(
mi
.
trim_start
&&
!
fastpath
)
{
while
(
start_trim
<
end_trim
)
{
if
(
t
->
input
[
i
+
start_trim
]
==
special
||
t
->
input
[
i
+
start_trim
]
==
t
->
dont_care
)
++
start_trim
;
else
break
;
}
}
// end_trim points to the last character we have to output
// find the first match, or add it
pos
=
find_packed
(
&
packed
,
&
t
->
input
[
i
+
start_trim
],
end_trim
-
start_trim
+
1
,
mi
.
aligned
,
fastpath
,
&
t
->
input
[
t
->
length
],
i
+
start_trim
,
t
->
replace_fallback_with_codepoint
);
// encode as a uval
if
(
!
mi
.
trim_end
)
{
if
(
end_trim
==
0
)
pos
=
special
;
else
pos
=
pos
|
0x80000000
;
}
else
{
assert
(
end_trim
<
size
&&
end_trim
>=
-
1
);
if
(
!
fastpath
)
assert
(
end_trim
<
size
-
1
);
// special always matches last one
assert
(
end_trim
<
size
&&
end_trim
+
1
>=
0
);
if
(
!
fastpath
)
assert
(
end_trim
+
1
<
size
);
if
(
mi
.
trim_start
)
trim
=
start_trim
*
256
+
(
end_trim
+
1
);
else
trim
=
end_trim
+
1
;
assert
(
pos
<
65536
);
// @TODO: if this triggers, just bail on this search path
pos
=
pos
+
(
trim
<<
16
);
}
newval
=
pos
;
stb_arr_push
(
specials
,
special
);
}
}
else
if
(
mi
.
trim_end
)
{
int
end_trim
=
size
-
1
;
int
start_trim
=
0
;
uval
pos
,
trim
;
while
(
end_trim
>=
0
&&
!
fastpath
)
if
(
t
->
input
[
i
+
end_trim
]
==
t
->
fallback
||
t
->
input
[
i
+
end_trim
]
==
t
->
dont_care
)
--
end_trim
;
else
break
;
if
(
mi
.
trim_start
&&
!
fastpath
)
{
while
(
start_trim
<
end_trim
)
{
if
(
t
->
input
[
i
+
start_trim
]
==
t
->
fallback
||
t
->
input
[
i
+
start_trim
]
==
t
->
dont_care
)
++
start_trim
;
else
break
;
}
}
// end_trim points to the last character we have to output, and can be -1
++
end_trim
;
// make exclusive at end
if
(
end_trim
==
0
&&
size
==
256
)
start_trim
=
end_trim
=
1
;
// we can't make encode a length from 0..256 in 8 bits, so restrict end_trim to 1..256
// find the first match, or add it
pos
=
find_packed
(
&
packed
,
&
t
->
input
[
i
+
start_trim
],
end_trim
-
start_trim
,
mi
.
aligned
,
fastpath
,
&
t
->
input
[
t
->
length
],
i
+
start_trim
,
t
->
replace_fallback_with_codepoint
);
assert
(
end_trim
<=
size
&&
end_trim
>=
0
);
if
(
size
==
256
)
assert
(
end_trim
-
1
<
256
&&
end_trim
-
1
>=
0
);
else
assert
(
end_trim
<
256
&&
end_trim
>=
0
);
if
(
size
==
256
)
--
end_trim
;
if
(
mi
.
trim_start
)
trim
=
start_trim
*
256
+
end_trim
;
else
trim
=
end_trim
;
assert
(
pos
<
65536
);
// @TODO: if this triggers, just bail on this search path
pos
=
pos
+
(
trim
<<
16
);
newval
=
pos
;
}
else
{
newval
=
find_packed
(
&
packed
,
&
t
->
input
[
i
],
size
,
mi
.
aligned
,
fastpath
,
&
t
->
input
[
t
->
length
],
i
,
t
->
replace_fallback_with_codepoint
);
}
if
(
mi
.
indirect
)
{
int
j
;
for
(
j
=
0
;
j
<
stb_arr_len
(
indirect
);
++
j
)
if
(
indirect
[
j
]
==
newval
)
break
;
if
(
j
==
stb_arr_len
(
indirect
))
stb_arr_push
(
indirect
,
newval
);
stb_arr_push
(
index
,
j
);
}
else
{
stb_arr_push
(
index
,
newval
);
}
}
// total up the new size for everything but the index table
extra_size
=
mi
.
overhead
*
weight
;
// not the actual overhead cost; a penalty to avoid excessive complexity
extra_size
+=
150
;
// per indirection
if
(
table_name
)
extra_size
=
0
;
if
(
t
->
has_sign
)
{
// 'packed' contains two values, which should be packed positive & negative for size
uval
maxv2
;
for
(
i
=
0
;
i
<
stb_arr_len
(
packed
);
++
i
)
if
(
packed
[
i
]
&
0x80000000
)
maxv2
=
stb_max
(
maxv2
,
packed
[
i
]);
else
maxv
=
stb_max
(
maxv
,
packed
[
i
]);
maxv
=
stb_max
(
maxv
,
maxv2
)
<<
1
;
}
else
{
maxv
=
0
;
for
(
i
=
0
;
i
<
stb_arr_len
(
packed
);
++
i
)
if
(
packed
[
i
]
>
maxv
&&
packed
[
i
]
!=
t
->
dont_care
)
maxv
=
packed
[
i
];
}
extra_size
+=
stb_arr_len
(
packed
)
*
(
t
->
splittable
?
size_for_max_number
(
maxv
)
:
size_for_max_number_aligned
(
maxv
));
if
(
table_name
)
{
if
(
t
->
splittable
)
output_table_with_trims
(
table_name
,
""
,
packed
,
stb_arr_len
(
packed
));
else
output_table
(
table_name
,
""
,
packed
,
stb_arr_len
(
packed
),
t
->
has_sign
,
NULL
);
}
maxv
=
0
;
for
(
i
=
0
;
i
<
stb_arr_len
(
specials
);
++
i
)
if
(
specials
[
i
]
>
maxv
)
maxv
=
specials
[
i
];
extra_size
+=
stb_arr_len
(
specials
)
*
size_for_max_number_aligned
(
maxv
);
if
(
table_name
)
output_table
(
table_name
,
"_default"
,
specials
,
stb_arr_len
(
specials
),
0
,
NULL
);
maxv
=
0
;
for
(
i
=
0
;
i
<
stb_arr_len
(
indirect
);
++
i
)
if
(
indirect
[
i
]
>
maxv
)
maxv
=
indirect
[
i
];
extra_size
+=
stb_arr_len
(
indirect
)
*
size_for_max_number
(
maxv
);
if
(
table_name
&&
stb_arr_len
(
indirect
))
{
if
(
mi
.
trim_end
)
output_table_with_trims
(
table_name
,
"_index"
,
indirect
,
stb_arr_len
(
indirect
));
else
{
assert
(
0
);
// this case should only trigger in very extreme circumstances
output_table
(
table_name
,
"_index"
,
indirect
,
stb_arr_len
(
indirect
),
0
,
NULL
);
}
mi
.
trim_end
=
mi
.
special
=
0
;
}
if
(
table_name
)
printf
(
"// above tables should be %d bytes
\n
"
,
extra_size
);
maxv
=
0
;
for
(
i
=
0
;
i
<
stb_arr_len
(
index
);
++
i
)
if
(
index
[
i
]
>
maxv
&&
index
[
i
]
!=
t
->
dont_care
)
maxv
=
index
[
i
];
newtab
.
splittable
=
mi
.
trim_end
;
newtab
.
input_size
=
newtab
.
splittable
?
size_for_max_number
(
maxv
)
:
size_for_max_number_aligned
(
maxv
);
newtab
.
input
=
index
;
newtab
.
length
=
stb_arr_len
(
index
);
newtab
.
inherited_storage
=
t
->
inherited_storage
+
extra_size
;
newtab
.
fastpath
=
0
;
newtab
.
depth
=
t
->
depth
+
1
;
stb_arr_free
(
indirect
);
stb_arr_free
(
packed
);
stb_arr_free
(
specials
);
return
newtab
;
}
result
pack_table
(
table
*
t
,
size_t
path
,
int
min_storage
)
{
int
i
;
result
best
;
best
.
size
=
t
->
inherited_storage
+
t
->
input_size
*
t
->
length
;
best
.
path
=
path
;
if
((
int
)
t
->
inherited_storage
>
min_storage
)
{
best
.
size
=
stb_max
(
best
.
size
,
t
->
inherited_storage
);
return
best
;
}
if
(
t
->
length
<=
256
||
t
->
depth
>=
4
)
{
//printf("%08x: %7d\n", best.path, best.size);
return
best
;
}
path
<<=
7
;
for
(
i
=
0
;
i
<
MODECOUNT
*
CLUSTERSIZECOUNT
;
++
i
)
{
table
newtab
;
result
r
;
newtab
=
pack_for_mode
(
t
,
i
,
0
);
r
=
pack_table
(
&
newtab
,
path
+
i
+
1
,
min_storage
);
if
(
r
.
size
<
best
.
size
)
best
=
r
;
stb_arr_free
(
newtab
.
input
);
//printf("Size: %6d + %6d\n", newtab.inherited_storage, newtab.input_size * newtab.length);
}
return
best
;
}
int
pack_table_by_modes
(
table
*
t
,
int
*
modes
)
{
table
s
=
*
t
;
while
(
*
modes
>
-
1
)
{
table
newtab
;
newtab
=
pack_for_mode
(
&
s
,
*
modes
,
0
);
if
(
s
.
input
!=
t
->
input
)
stb_arr_free
(
s
.
input
);
s
=
newtab
;
++
modes
;
}
return
s
.
inherited_storage
+
s
.
input_size
*
s
.
length
;
}
int
strip_table
(
table
*
t
,
int
exceptions
)
{
uval
terminal_value
;
int
p
=
t
->
length
-
1
;
while
(
t
->
input
[
p
]
==
t
->
dont_care
)
--
p
;
terminal_value
=
t
->
input
[
p
];
while
(
p
>=
0x10000
)
{
if
(
t
->
input
[
p
]
!=
terminal_value
&&
t
->
input
[
p
]
!=
t
->
dont_care
)
{
if
(
exceptions
)
--
exceptions
;
else
break
;
}
--
p
;
}
return
p
+
1
;
// p is a character we must output
}
void
optimize_table
(
table
*
t
,
char
*
table_name
)
{
int
modelist
[
3
]
=
{
85
,
-
1
};
int
modes
[
8
];
int
num_modes
=
0
;
int
decent_size
;
result
r
;
size_t
path
;
table
s
;
// strip tail end of table
int
orig_length
=
t
->
length
;
int
threshhold
=
0xffff
;
int
p
=
strip_table
(
t
,
2
);
int
len_saved
=
t
->
length
-
p
;
if
(
len_saved
>=
threshhold
)
{
t
->
length
=
p
;
while
(
p
>
0x10000
)
{
p
=
strip_table
(
t
,
0
);
len_saved
=
t
->
length
-
p
;
if
(
len_saved
<
0x10000
)
break
;
len_saved
=
orig_length
-
p
;
if
(
len_saved
<
threshhold
)
break
;
threshhold
*=
2
;
}
}
t
->
depth
=
1
;
// find size of table if we use path 86
decent_size
=
pack_table_by_modes
(
t
,
modelist
);
#if 1
// find best packing of remainder of table by exploring tree of packings
r
=
pack_table
(
t
,
0
,
decent_size
);
// use the computed 'path' to evaluate and output tree
path
=
r
.
path
;
#else
path
=
86
;
//90;//132097;
#endif
while
(
path
)
{
modes
[
num_modes
++
]
=
(
path
&
127
)
-
1
;
path
>>=
7
;
}
printf
(
"// modes: %d
\n
"
,
r
.
path
);
s
=
*
t
;
while
(
num_modes
>
0
)
{
char
name
[
256
];
sprintf
(
name
,
"%s_%d"
,
table_name
,
num_modes
+
1
);
--
num_modes
;
s
=
pack_for_mode
(
&
s
,
modes
[
num_modes
],
name
);
}
// output the final table as-is
if
(
s
.
splittable
)
output_table_with_trims
(
table_name
,
"_1"
,
s
.
input
,
s
.
length
);
else
output_table
(
table_name
,
"_1"
,
s
.
input
,
s
.
length
,
0
,
NULL
);
}
uval
unicode_table
[
0x110000
];
typedef
struct
{
uval
lo
,
hi
;
}
char_range
;
char_range
get_range
(
char
*
str
)
{
char_range
cr
;
char
*
p
;
cr
.
lo
=
strtol
(
str
,
&
p
,
16
);
p
=
stb_skipwhite
(
p
);
if
(
*
p
==
'.'
)
cr
.
hi
=
strtol
(
p
+
2
,
NULL
,
16
);
else
cr
.
hi
=
cr
.
lo
;
return
cr
;
}
char
*
skip_semi
(
char
*
s
,
int
count
)
{
while
(
count
)
{
s
=
strchr
(
s
,
';'
);
assert
(
s
!=
NULL
);
++
s
;
--
count
;
}
return
s
;
}
int
main
(
int
argc
,
char
**
argv
)
{
table
t
;
uval
maxv
=
0
;
int
i
,
n
=
0
;
char
**
s
=
stb_stringfile
(
"../../data/UnicodeData.txt"
,
&
n
);
assert
(
s
);
for
(
i
=
0
;
i
<
n
;
++
i
)
{
if
(
s
[
i
][
0
]
==
'#'
||
s
[
i
][
0
]
==
'\n'
||
s
[
i
][
0
]
==
0
)
;
else
{
char_range
cr
=
get_range
(
s
[
i
]);
char
*
t
=
skip_semi
(
s
[
i
],
13
);
uval
j
,
v
;
if
(
*
t
==
';'
||
*
t
==
'\n'
||
*
t
==
0
)
v
=
0
;
else
{
v
=
strtol
(
t
,
NULL
,
16
);
if
(
v
<
65536
)
{
maxv
=
stb_max
(
v
,
maxv
);
for
(
j
=
cr
.
lo
;
j
<=
cr
.
hi
;
++
j
)
{
unicode_table
[
j
]
=
v
;
//printf("%06x => %06x\n", j, v);
}
}
}
}
}
t
.
depth
=
0
;
t
.
dont_care
=
UVAL_DONT_CARE_DEFAULT
;
t
.
fallback
=
0
;
t
.
fastpath
=
256
;
t
.
inherited_storage
=
0
;
t
.
has_sign
=
0
;
t
.
splittable
=
0
;
t
.
input
=
unicode_table
;
t
.
input_size
=
size_for_max_number
(
maxv
);
t
.
length
=
0x110000
;
t
.
replace_fallback_with_codepoint
=
1
;
optimize_table
(
&
t
,
"stbu_upppercase"
);
return
0
;
}
tools/unicode/unicode.dsp
0 → 100644
浏览文件 @
50479cb0
# Microsoft Developer Studio Project File - Name="unicode" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=unicode - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "unicode.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "unicode.mak" CFG="unicode - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "unicode - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "unicode - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "unicode - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
!ELSEIF "$(CFG)" == "unicode - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "unicode - Win32 Release"
# Name "unicode - Win32 Debug"
# Begin Source File
SOURCE=..\unicode.c
# End Source File
# End Target
# End Project
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录