|
|
@@ -3,13 +3,28 @@ package packer
|
|
|
|
|
|
import (
|
|
|
"fmt"
|
|
|
+ "log"
|
|
|
+ "math"
|
|
|
+ "os"
|
|
|
+ "time"
|
|
|
|
|
|
+ "p78git.ddns.net/svi/packer/internal/packer/dict_keys"
|
|
|
+ "p78git.ddns.net/svi/packer/internal/packer/freq_pair"
|
|
|
+ "p78git.ddns.net/svi/packer/internal/packer/frequencer"
|
|
|
"p78git.ddns.net/svi/packer/pkg/types"
|
|
|
)
|
|
|
|
|
|
// Packer -- упаковщик сервиса
|
|
|
type Packer struct {
|
|
|
- serv types.IService
|
|
|
+ serv types.IService
|
|
|
+ dictKeys types.IDictKeys // Словарь ключей
|
|
|
+ freqPair *freq_pair.FreqPair // Частотная пара
|
|
|
+ frequencer types.IFrequencer // Подбор частотной пары
|
|
|
+ binData []uint16 // То, что останется после замен
|
|
|
+ timeTotal float32 // Общее время в сек
|
|
|
+ totalChange int // Общее число замен
|
|
|
+ originSize int // Оригинальный размер
|
|
|
+ binNew []uint16 // Буфер новых данных
|
|
|
}
|
|
|
|
|
|
// NewPacker -- возвращает ноый пакер
|
|
|
@@ -18,7 +33,156 @@ func NewPacker(serv types.IService) (*Packer, error) {
|
|
|
return nil, fmt.Errorf("NewPacker(): IService==nil")
|
|
|
}
|
|
|
sf := &Packer{
|
|
|
- serv: serv,
|
|
|
+ serv: serv,
|
|
|
+ dictKeys: dict_keys.NewDictKeys(),
|
|
|
+ freqPair: &freq_pair.FreqPair{},
|
|
|
+ binData: []uint16{},
|
|
|
+ binNew: []uint16{0, 0, 0},
|
|
|
}
|
|
|
+ var err error
|
|
|
+ sf.frequencer, err = frequencer.NewFrequencer(sf)
|
|
|
+ if err != nil {
|
|
|
+ return nil, fmt.Errorf("NewPacker(): in create IFrequencer, err=\n\t%w", err)
|
|
|
+ }
|
|
|
+ _ = types.IPacker(sf)
|
|
|
return sf, nil
|
|
|
}
|
|
|
+
|
|
|
+// Run -- запускает упаковку
|
|
|
+func (sf *Packer) Run() error {
|
|
|
+ log.Printf("Packer.Run()\n")
|
|
|
+ { // Чтение файла
|
|
|
+ fileName := os.Getenv("PACK_FILE")
|
|
|
+ if fileName == "" {
|
|
|
+ return fmt.Errorf("Packer.Run(): env PACK_FILE not set")
|
|
|
+ }
|
|
|
+ binData, err := os.ReadFile(fileName)
|
|
|
+ if err != nil {
|
|
|
+ return fmt.Errorf("Packer.Run(): in read %q, err=\n\t%w", fileName, err)
|
|
|
+ }
|
|
|
+ sf.originSize = len(binData)
|
|
|
+ for _, val := range binData {
|
|
|
+ sf.binData = append(sf.binData, uint16(val))
|
|
|
+ }
|
|
|
+ log.Printf("Packer.Run(): len(%q)=%v\n", fileName, len(sf.binData))
|
|
|
+ }
|
|
|
+ round := 1
|
|
|
+ for { // Главный цикл сжатия
|
|
|
+ log.Printf("Packer.Run(): round=%v, lenDict=%v\n", round, sf.dictKeys.Len())
|
|
|
+ if !sf.round() {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ round++
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// Serv -- возвращает сервис
|
|
|
+func (sf *Packer) Serv() types.IService {
|
|
|
+ return sf.serv
|
|
|
+}
|
|
|
+
|
|
|
+// BinData -- возвращает бинарны данные для упаковки
|
|
|
+func (sf *Packer) BinData() []uint16 {
|
|
|
+ return sf.binData
|
|
|
+}
|
|
|
+
|
|
|
+// DictKeys -- возвращает словарь ключей для подстановки
|
|
|
+func (sf *Packer) DictKeys() types.IDictKeys {
|
|
|
+ return sf.dictKeys
|
|
|
+}
|
|
|
+
|
|
|
+// Выполняет раунд сжатия
|
|
|
+func (sf *Packer) round() bool {
|
|
|
+ timeBeg := time.Now().Local().UnixMilli()
|
|
|
+ defer func() {
|
|
|
+ timeEnd := time.Now().Local().UnixMilli()
|
|
|
+ timeDelta := float32(timeEnd-timeBeg) / 1000
|
|
|
+ sf.timeTotal += timeDelta
|
|
|
+ ratio := (float32(len(sf.binData)) - float32(sf.originSize)) / float32(sf.originSize) * 100
|
|
|
+ log.Printf("Packer.Round(): timeTotal=%0.2fsec, timeRound=%0.2fsec, ration=%0.2f%%, totalChange=%v\n\n",
|
|
|
+ sf.timeTotal,
|
|
|
+ timeDelta,
|
|
|
+ ratio,
|
|
|
+ sf.totalChange)
|
|
|
+ }()
|
|
|
+ sf.dictUp()
|
|
|
+ if err := sf.frequencer.Run(); err != nil {
|
|
|
+ log.Printf("Packer.round(): in work IFrequencer, err=\n\t%v\n", err)
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ sf.freqPair.SetKeys(sf.frequencer.Keys())
|
|
|
+ keyNext, err := sf.keyNext()
|
|
|
+ if err != nil {
|
|
|
+ log.Printf("Packer.round(): limit keys, err=\n\t%v\n", err)
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ sf.changeKey(keyNext)
|
|
|
+ return true
|
|
|
+}
|
|
|
+
|
|
|
+// Заменяет частотную пару на указанный ключ
|
|
|
+func (sf *Packer) changeKey(key uint16) {
|
|
|
+ sf.binNew = sf.binNew[:0]
|
|
|
+ val0 := sf.binData[0]
|
|
|
+ ind := 1
|
|
|
+ val1 := sf.binData[ind]
|
|
|
+ fnNext := func() bool { // вычисляет сдвиг после замены
|
|
|
+ sf.binNew = append(sf.binNew, key)
|
|
|
+ if ind+1 >= len(sf.binData) { // Достигнут предел прохода
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ ind++
|
|
|
+ val0 = sf.binData[ind]
|
|
|
+ if ind+1 >= len(sf.binData) { // Достигнут предел прохода
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ ind++
|
|
|
+ val1 = sf.binData[ind]
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ key0 := sf.freqPair.Key0_
|
|
|
+ key1 := sf.freqPair.Key1_
|
|
|
+ for ind < len(sf.binData) {
|
|
|
+ val1 = sf.binData[ind]
|
|
|
+ if val0 == key0 && val1 == key1 {
|
|
|
+ fnNext()
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ sf.binNew = append(sf.binNew, val0)
|
|
|
+ val0 = val1
|
|
|
+ ind++
|
|
|
+ }
|
|
|
+ countChange := len(sf.binData) - len(sf.binNew)
|
|
|
+ sf.totalChange += countChange
|
|
|
+ log.Printf("Packer.changeKey(): len{old=%v, new=%v}, numChange=%v\n",
|
|
|
+ len(sf.binData),
|
|
|
+ len(sf.binNew),
|
|
|
+ countChange)
|
|
|
+ sf.binData = sf.binNew
|
|
|
+}
|
|
|
+
|
|
|
+// Ищёт следующий свободный ключ
|
|
|
+func (sf *Packer) keyNext() (uint16, error) {
|
|
|
+ key := uint16(0)
|
|
|
+ for {
|
|
|
+ if !sf.dictKeys.IsExists(key) {
|
|
|
+ return key, nil
|
|
|
+ }
|
|
|
+ key++
|
|
|
+ if key == math.MaxUint16 {
|
|
|
+ return 0, fmt.Errorf("Packer.keyNext(): key up to limit uint32")
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Собирает словарь ключей из текста
|
|
|
+func (sf *Packer) dictUp() {
|
|
|
+ // Собрать встречающиеся ключи
|
|
|
+ for _, val := range sf.binData {
|
|
|
+ if !sf.dictKeys.IsExists(val) {
|
|
|
+ sf.dictKeys.Add(val)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|