e2720c09f7
После добавления NO_PROXY в bash-окружение (proxy.golang.org, goproxy.cn, *.golang.org, github.com и пр.) штатные модули Go стали доступны напрямую — zetit-прокси теперь обходится только для внутренних/публичных хостов, которым нужен внутренний прокси, и пропускает только нужное. Заменено: - internal/nsdxml/codec.go: 90+ строк собственной CP1251-таблицы → тонкая обёртка над golang.org/x/text/encoding/charmap.Windows1251 - go.mod: добавлен require golang.org/x/text v0.22.0 - internal/nsdxml/README.md: пометка о причине истории и текущей реализации Покрытие nsdxml сохранилось, make ci зелёный. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
70 lines
2.6 KiB
Go
70 lines
2.6 KiB
Go
package nsdxml
|
||
|
||
import (
|
||
"bytes"
|
||
"encoding/xml"
|
||
"errors"
|
||
"fmt"
|
||
"io"
|
||
"strings"
|
||
|
||
"golang.org/x/text/encoding/charmap"
|
||
)
|
||
|
||
// xmlProlog — пролог windows-1251 XML, который мы пишем при сериализации.
|
||
const xmlProlog = `<?xml version="1.0" encoding="windows-1251"?>` + "\n"
|
||
|
||
// ErrUnmappable возвращается, когда руна не имеет представления в windows-1251.
|
||
var ErrUnmappable = errors.New("nsdxml: rune не представим в windows-1251")
|
||
|
||
// DecodeWindows1251 преобразует байты в кодировке windows-1251 в UTF-8.
|
||
// Использует штатную реализацию golang.org/x/text/encoding/charmap.
|
||
func DecodeWindows1251(src []byte) []byte {
|
||
out, _ := charmap.Windows1251.NewDecoder().Bytes(src)
|
||
return out
|
||
}
|
||
|
||
// EncodeWindows1251 преобразует UTF-8 байты в windows-1251. Если в
|
||
// исходной строке встречается руна, не выразимая в CP1251, возвращает
|
||
// ErrUnmappable с указанием смещения.
|
||
func EncodeWindows1251(src []byte) ([]byte, error) {
|
||
out, err := charmap.Windows1251.NewEncoder().Bytes(src)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("%w: %w", ErrUnmappable, err)
|
||
}
|
||
return out, nil
|
||
}
|
||
|
||
// CharsetReader пригоден к использованию в xml.Decoder.CharsetReader.
|
||
// Для charset "windows-1251"/"cp1251" возвращает декодирующий reader.
|
||
// Для UTF-8 и неуказанного charset — пробрасывает поток без изменений.
|
||
func CharsetReader(charset string, input io.Reader) (io.Reader, error) {
|
||
switch strings.ToLower(charset) {
|
||
case "windows-1251", "cp1251":
|
||
return charmap.Windows1251.NewDecoder().Reader(input), nil
|
||
case "", "utf-8", "utf8":
|
||
return input, nil
|
||
}
|
||
return nil, fmt.Errorf("nsdxml: неизвестная кодировка %q", charset)
|
||
}
|
||
|
||
// Marshal сериализует v в XML, добавляет пролог с encoding="windows-1251"
|
||
// и преобразует поток в windows-1251.
|
||
func Marshal(v any) ([]byte, error) {
|
||
utf8Body, err := xml.MarshalIndent(v, "", "\t")
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
withProlog := append([]byte(xmlProlog), utf8Body...)
|
||
return EncodeWindows1251(withProlog)
|
||
}
|
||
|
||
// Unmarshal разбирает XML (windows-1251 или UTF-8) в v. Использует
|
||
// CharsetReader для перекодирования входа, если в прологе указана
|
||
// windows-1251.
|
||
func Unmarshal(data []byte, v any) error {
|
||
dec := xml.NewDecoder(bytes.NewReader(data))
|
||
dec.CharsetReader = CharsetReader
|
||
return dec.Decode(v)
|
||
}
|