Clash.Meta/rules/provider/mrs_converter.go

121 lines
2.3 KiB
Go
Raw Normal View History

2024-07-26 22:30:42 +08:00
package provider
import (
2024-07-27 10:36:11 +08:00
"encoding/binary"
2024-07-27 23:54:28 +08:00
"errors"
"fmt"
2024-07-26 22:30:42 +08:00
"io"
"os"
P "github.com/metacubex/mihomo/constant/provider"
"github.com/klauspost/compress/zstd"
)
func ConvertToMrs(buf []byte, behavior P.RuleBehavior, format P.RuleFormat, w io.Writer) (err error) {
strategy := newStrategy(behavior, nil)
strategy, err = rulesParse(buf, strategy, format)
if err != nil {
return err
}
2024-07-27 23:54:28 +08:00
if strategy.Count() == 0 {
return errors.New("empty rule")
}
2024-07-26 22:30:42 +08:00
if _strategy, ok := strategy.(mrsRuleStrategy); ok {
if format == P.MrsRule { // export to TextRule
_strategy.DumpMrs(func(key string) bool {
_, err = fmt.Fprintln(w, key)
if err != nil {
return false
}
return true
})
return nil
}
2024-07-26 22:30:42 +08:00
var encoder *zstd.Encoder
2024-09-07 20:22:21 +08:00
encoder, err = zstd.NewWriter(w, zstd.WithEncoderLevel(zstd.SpeedBestCompression))
2024-07-26 22:30:42 +08:00
if err != nil {
return err
}
defer func() {
zstdErr := encoder.Close()
if err == nil {
err = zstdErr
}
}()
2024-07-27 10:36:11 +08:00
// header
_, err = encoder.Write(MrsMagicBytes[:])
if err != nil {
return err
}
// behavior
_behavior := []byte{behavior.Byte()}
_, err = encoder.Write(_behavior[:])
if err != nil {
return err
}
// count
count := int64(_strategy.Count())
err = binary.Write(encoder, binary.BigEndian, count)
if err != nil {
return err
}
// extra (reserved for future using)
var extra []byte
err = binary.Write(encoder, binary.BigEndian, int64(len(extra)))
if err != nil {
return err
}
_, err = encoder.Write(extra)
if err != nil {
return err
}
2024-07-26 22:30:42 +08:00
return _strategy.WriteMrs(encoder)
} else {
return ErrInvalidFormat
}
}
func ConvertMain(args []string) {
if len(args) > 3 {
behavior, err := P.ParseBehavior(args[0])
if err != nil {
panic(err)
}
format, err := P.ParseRuleFormat(args[1])
if err != nil {
panic(err)
}
source := args[2]
target := args[3]
sourceFile, err := os.ReadFile(source)
if err != nil {
panic(err)
}
targetFile, err := os.OpenFile(target, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
panic(err)
}
err = ConvertToMrs(sourceFile, behavior, format, targetFile)
if err != nil {
panic(err)
}
err = targetFile.Close()
if err != nil {
panic(err)
}
} else {
panic("Usage: convert-ruleset <behavior> <format> <source file> <target file>")
}
}