diff options
| -rwxr-xr-x | scripts/macos-package.sh | 64 |
1 files changed, 59 insertions, 5 deletions
diff --git a/scripts/macos-package.sh b/scripts/macos-package.sh index 3255898..ebe9e2a 100755 --- a/scripts/macos-package.sh +++ b/scripts/macos-package.sh @@ -48,6 +48,27 @@ sha256() { printf '%s\n' "${output%% *}" } +utf8_char_count() { + # 不依赖 locale 的 UTF-8 码点计数:只数每个码点的首字节 + # (ASCII <128,或 110xxxxx/1110xxxx/11110xxx 前导字节),续字节 10xxxxxx 忽略。 + printf '%s' "$1" | od -An -t u1 | awk ' + { for (i = 1; i <= NF; i++) { b = $i; if (b < 128 || (b >= 192 && b < 248)) n++ } } + END { print n + 0 }' +} + +png_dimensions() { + # 从 PNG IHDR 读取宽高(大端 4 字节,偏移 16/20),只依赖 od。 + local bytes size + bytes="$(od -An -t u1 -j 16 -N 8 "$1" | tr -s ' ' '\n' | sed '/^$/d' | paste -sd' ')" + read -r b0 b1 b2 b3 b4 b5 b6 b7 <<< "$bytes" + if [[ -z "${b7:-}" ]]; then + return 1 + fi + printf '%s %s\n' \ + "$(( b0 * 16777216 + b1 * 65536 + b2 * 256 + b3 ))" \ + "$(( b4 * 16777216 + b5 * 65536 + b6 * 256 + b7 ))" +} + write_launcher() { local launcher_path="$1" cat > "$launcher_path" <<'EOF' @@ -276,17 +297,50 @@ for rid in osx-arm64 osx-x64; do exit 1 fi done + # CJK 清单不再硬编码行数:与图集网格自洽(16 列,行数覆盖字符数且无空行), + # 并校验非空、每行恰 1 个字符、字符唯一,避免图集增长后打包悄悄过期。 + if [[ ! -s "$app_dir/Contents/MacOS/Assets/cjk-glyphs.txt" ]]; then + printf 'BLOCKED: packaged CJK manifest for %s is empty\n' "$rid" >&2 + exit 1 + fi mapfile -t cjk_manifest_lines < "$app_dir/Contents/MacOS/Assets/cjk-glyphs.txt" - if [[ "${#cjk_manifest_lines[@]}" -ne 188 ]]; then - printf 'BLOCKED: packaged CJK manifest for %s contains %s lines; expected 188\n' "$rid" "${#cjk_manifest_lines[@]}" >&2 + if [[ "${#cjk_manifest_lines[@]}" -eq 0 ]]; then + printf 'BLOCKED: packaged CJK manifest for %s is empty\n' "$rid" >&2 exit 1 fi - for cjk_manifest_line in "${cjk_manifest_lines[@]}"; do - if [[ ${#cjk_manifest_line} -ne 1 ]]; then - printf 'BLOCKED: packaged CJK manifest for %s contains a line that is not one character\n' "$rid" >&2 + declare -A cjk_seen_characters=() + for index in "${!cjk_manifest_lines[@]}"; do + cjk_manifest_line="${cjk_manifest_lines[$index]}" + if [[ "$(utf8_char_count "$cjk_manifest_line")" -ne 1 ]]; then + printf 'BLOCKED: packaged CJK manifest for %s line %s is not one character\n' "$rid" "$((index + 1))" >&2 exit 1 fi + if [[ "${cjk_seen_characters[$cjk_manifest_line]+present}" ]]; then + printf 'BLOCKED: packaged CJK manifest for %s has a duplicate character on line %s\n' "$rid" "$((index + 1))" >&2 + exit 1 + fi + cjk_seen_characters[$cjk_manifest_line]=1 done + cjk_character_count="${#cjk_manifest_lines[@]}" + cjk_cell_pixels=24 + cjk_expected_columns=16 + if ! read -r cjk_atlas_width cjk_atlas_height < <(png_dimensions "$app_dir/Contents/MacOS/Assets/cjk-glyph-atlas.png"); then + printf 'BLOCKED: cannot read packaged CJK atlas dimensions for %s\n' "$rid" >&2 + exit 1 + fi + cjk_columns=$(( cjk_atlas_width / cjk_cell_pixels )) + cjk_rows=$(( cjk_atlas_height / cjk_cell_pixels )) + cjk_capacity=$(( cjk_columns * cjk_rows )) + if (( cjk_columns != cjk_expected_columns )); then + printf 'BLOCKED: packaged CJK atlas for %s has %s columns; expected %s\n' \ + "$rid" "$cjk_columns" "$cjk_expected_columns" >&2 + exit 1 + fi + if (( cjk_capacity < cjk_character_count || cjk_capacity - cjk_character_count >= cjk_columns )); then + printf 'BLOCKED: packaged CJK atlas grid %sx%s (%s cells) is inconsistent with manifest %s characters for %s\n' \ + "$cjk_columns" "$cjk_rows" "$cjk_capacity" "$cjk_character_count" "$rid" >&2 + exit 1 + fi if ! file -b "$app_dir/Contents/MacOS/LivingVillage.Desktop" >> "$mach_o_report"; then printf 'BLOCKED: failed to inspect bundled apphost for %s\n' "$rid" >&2 |
