|
|
|
|
@ -30,17 +30,21 @@ import (
|
|
|
|
|
"activething.com/go/gogo/packs"
|
|
|
|
|
"encoding/base64"
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"fmt"
|
|
|
|
|
"reflect"
|
|
|
|
|
"time"
|
|
|
|
|
"unicode/utf8"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const notDetectingCycles = 100
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type (
|
|
|
|
|
|
|
|
|
|
Packer struct {
|
|
|
|
|
options Options
|
|
|
|
|
state *packs.State
|
|
|
|
|
checks map[any]struct{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -49,7 +53,7 @@ type (
|
|
|
|
|
func NewPacker (options ...opts.OptionFnc[Packer]) *Packer {
|
|
|
|
|
return opts.Apply(&Packer{
|
|
|
|
|
options: Options{
|
|
|
|
|
Flags: JSONFlagQuote | JSONFlagEscapeHTML,
|
|
|
|
|
Flags: JSONFlagQuote | JSONFlagEscapeHTML | JSONByteSliceAsBinary,
|
|
|
|
|
dateLayout: time.RFC822Z,
|
|
|
|
|
},
|
|
|
|
|
state : packs.NewState(),
|
|
|
|
|
@ -59,7 +63,9 @@ func NewPacker (options ...opts.OptionFnc[Packer]) *Packer {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (p *Packer) Bytes () []byte {
|
|
|
|
|
defer p.Reset()
|
|
|
|
|
if p.options.ResetOnRead() {
|
|
|
|
|
defer p.Reset()
|
|
|
|
|
}
|
|
|
|
|
return append([]byte(nil),p.state.Bytes()...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -83,13 +89,12 @@ func (p *Packer) Pack (value any) {
|
|
|
|
|
|
|
|
|
|
if value == nil {
|
|
|
|
|
if p.options.Quote() {
|
|
|
|
|
p.state.WriteByte('"')
|
|
|
|
|
_ = p.state.WriteByte('"')
|
|
|
|
|
}
|
|
|
|
|
p.state.Write(G.nullValue)
|
|
|
|
|
_,_ = p.state.Write(G.nullValue)
|
|
|
|
|
if p.options.Quote() {
|
|
|
|
|
p.state.WriteByte('"')
|
|
|
|
|
_ = p.state.WriteByte('"')
|
|
|
|
|
}
|
|
|
|
|
p.state.Node.Count++
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -113,16 +118,17 @@ func (p *Packer) Pack (value any) {
|
|
|
|
|
case float32: p.packFloat(float64(v),32)
|
|
|
|
|
case float64: p.packFloat(v,64)
|
|
|
|
|
|
|
|
|
|
case time.Time : p.PackDate(v)
|
|
|
|
|
|
|
|
|
|
case reflect.Value : p.Pack(v.Elem())
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
if pb,is := value.(packs.Packabler); is {
|
|
|
|
|
d,e := pb.Build(p)
|
|
|
|
|
d, e := pb.Build(p)
|
|
|
|
|
if p.state.SetError(e) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
_,_ = p.state.Write(d)
|
|
|
|
|
p.state.Node.Count++
|
|
|
|
|
_, _ = p.state.Write(d)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if ms,is := value.(json.Marshaler); is {
|
|
|
|
|
@ -131,26 +137,21 @@ func (p *Packer) Pack (value any) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
_,_ = p.state.Write(d)
|
|
|
|
|
p.state.Node.Count++
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rv := reflect.ValueOf(value)
|
|
|
|
|
switch rv.Kind() {
|
|
|
|
|
case reflect.Slice,reflect.Array :
|
|
|
|
|
case reflect.Slice, reflect.Array:
|
|
|
|
|
p.packListReflected(rv)
|
|
|
|
|
return
|
|
|
|
|
case reflect.Map :
|
|
|
|
|
case reflect.Map:
|
|
|
|
|
p.packMapReflected(rv)
|
|
|
|
|
return
|
|
|
|
|
case reflect.Struct:
|
|
|
|
|
p.packObjectReflected(rv)
|
|
|
|
|
return
|
|
|
|
|
default:
|
|
|
|
|
p.state.SetError(packs.G.ErrUnsupportedType)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p.state.SetError(packs.G.ErrUnsupportedType)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -173,7 +174,7 @@ func (p *Packer) PackRaw (value []byte) {
|
|
|
|
|
_ = p.state.WriteByte('"')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p.state.Node.Count++
|
|
|
|
|
//p.state.Node.Count++
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -208,36 +209,34 @@ func (p *Packer) PackBinary (value []byte) {
|
|
|
|
|
}
|
|
|
|
|
_ = p.state.WriteByte('"')
|
|
|
|
|
|
|
|
|
|
p.state.Node.Count++
|
|
|
|
|
//p.state.Node.Count++
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Packer) PackString (value string) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (p *Packer) PackString(value string) {
|
|
|
|
|
|
|
|
|
|
if p.state.Error != nil {
|
|
|
|
|
panic(p.state.Error)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(value) == 0 {
|
|
|
|
|
p.state.Write2Byte('"','"')
|
|
|
|
|
} else {
|
|
|
|
|
p.packString(value,p.options.EscapeHTML())
|
|
|
|
|
//p.state.Node.Count++
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p.state.Node.Count++
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Packer) packString(s string, scapeHTML bool) {
|
|
|
|
|
|
|
|
|
|
_ = p.state.WriteByte('"')
|
|
|
|
|
start := 0
|
|
|
|
|
for i := 0; i < len(s); {
|
|
|
|
|
if b := s[i]; b < utf8.RuneSelf {
|
|
|
|
|
if !G.jsonChars[b].isHtmlUnsafe() || (!scapeHTML && !G.jsonChars[b].isUnsafe()) {
|
|
|
|
|
for i := 0; i < len(value); {
|
|
|
|
|
if b := value[i]; b < utf8.RuneSelf {
|
|
|
|
|
if !G.jsonChars[b].isHtmlUnsafe() || (!p.options.EscapeHTML() && !G.jsonChars[b].isUnsafe()) {
|
|
|
|
|
i++
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if start < i {
|
|
|
|
|
_,_ = p.state.WriteString(s[start:i])
|
|
|
|
|
_,_ = p.state.WriteString(value[start:i])
|
|
|
|
|
}
|
|
|
|
|
_ = p.state.WriteByte('\\')
|
|
|
|
|
switch b {
|
|
|
|
|
@ -253,10 +252,10 @@ func (p *Packer) packString(s string, scapeHTML bool) {
|
|
|
|
|
start = i
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
c, size := utf8.DecodeRuneInString(s[i:])
|
|
|
|
|
c, size := utf8.DecodeRuneInString(value[i:])
|
|
|
|
|
if c == utf8.RuneError && size == 1 {
|
|
|
|
|
if start < i {
|
|
|
|
|
_,_ = p.state.WriteString(s[start:i])
|
|
|
|
|
_,_ = p.state.WriteString(value[start:i])
|
|
|
|
|
}
|
|
|
|
|
_,_ = p.state.WriteString(`\ufffd`)
|
|
|
|
|
i += size
|
|
|
|
|
@ -266,7 +265,7 @@ func (p *Packer) packString(s string, scapeHTML bool) {
|
|
|
|
|
|
|
|
|
|
if c == '\u2028' || c == '\u2029' {
|
|
|
|
|
if start < i {
|
|
|
|
|
_,_ = p.state.WriteString(s[start:i])
|
|
|
|
|
_,_ = p.state.WriteString(value[start:i])
|
|
|
|
|
}
|
|
|
|
|
_,_ = p.state.WriteString(`\u202`)
|
|
|
|
|
_ = p.state.WriteByte(G.hex[c&0xF])
|
|
|
|
|
@ -276,10 +275,13 @@ func (p *Packer) packString(s string, scapeHTML bool) {
|
|
|
|
|
}
|
|
|
|
|
i += size
|
|
|
|
|
}
|
|
|
|
|
if start < len(s) {
|
|
|
|
|
_,_ = p.state.WriteString(s[start:])
|
|
|
|
|
if start < len(value) {
|
|
|
|
|
_,_ = p.state.WriteString(value[start:])
|
|
|
|
|
}
|
|
|
|
|
_ = p.state.WriteByte('"')
|
|
|
|
|
|
|
|
|
|
//p.state.Node.Count++
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -303,7 +305,7 @@ func (p *Packer) PackBool (value bool) {
|
|
|
|
|
_ = p.state.WriteByte('"')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p.state.Node.Count++
|
|
|
|
|
//p.state.Node.Count++
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Packer) PackInt8 (value int8) { p.PackInt64(int64(value)) }
|
|
|
|
|
@ -326,7 +328,7 @@ func (p *Packer) PackInt64 (value int64) {
|
|
|
|
|
_ = p.state.WriteByte('"')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p.state.Node.Count++
|
|
|
|
|
//p.state.Node.Count++
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Packer) PackUInt8 (value uint8 ) { p.PackUInt64(uint64(value)) }
|
|
|
|
|
@ -349,7 +351,7 @@ func (p *Packer) PackUInt64 (value uint64) {
|
|
|
|
|
_ = p.state.WriteByte('"')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p.state.Node.Count++
|
|
|
|
|
//p.state.Node.Count++
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Packer) PackFloat32 (value float32) { p.packFloat(float64(value),32) }
|
|
|
|
|
@ -372,7 +374,7 @@ func (p *Packer) packFloat (value float64, bits int) {
|
|
|
|
|
_ = p.state.WriteByte('"')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p.state.Node.Count++
|
|
|
|
|
//p.state.Node.Count++
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -387,7 +389,7 @@ func (p *Packer) PackDate (value time.Time) {
|
|
|
|
|
}))
|
|
|
|
|
_ = p.state.WriteByte('"')
|
|
|
|
|
|
|
|
|
|
p.state.Node.Count++
|
|
|
|
|
//p.state.Node.Count++
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -414,19 +416,12 @@ func (p *Packer) packCompound(kind packs.NodeKind, opening, closing byte, buildF
|
|
|
|
|
}
|
|
|
|
|
}(&dn)
|
|
|
|
|
|
|
|
|
|
//p.addSep()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if p.state.Open(kind) {
|
|
|
|
|
fmt.Printf("Node Count %d\n",p.state.Node.Count)
|
|
|
|
|
_ = p.state.WriteByte(opening)
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
if !p.state.SetValue() {
|
|
|
|
|
panic(p.state.Error)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
buildFnc(p)
|
|
|
|
|
|
|
|
|
|
if p.state.Error == nil {
|
|
|
|
|
if p.state.Close() {
|
|
|
|
|
_ = p.state.WriteByte(closing)
|
|
|
|
|
@ -470,10 +465,10 @@ func (p *Packer) addKey (key any, call func(*Packer)) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p.packString(ks,p.options.EscapeHTML())
|
|
|
|
|
p.PackString(ks)
|
|
|
|
|
_ = p.state.WriteByte(':')
|
|
|
|
|
call(p)
|
|
|
|
|
p.state.Node.Count++
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -487,17 +482,87 @@ func (p *Packer) addField (name string, call func(*Packer)) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p.packString(name,p.options.EscapeHTML())
|
|
|
|
|
p.PackString(name)
|
|
|
|
|
_ = p.state.WriteByte(':')
|
|
|
|
|
call(p)
|
|
|
|
|
p.state.Node.Count++
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (p *Packer) packListReflected (value reflect.Value) {
|
|
|
|
|
//todo
|
|
|
|
|
if value.IsNil() {
|
|
|
|
|
_,_ = p.state.Write(G.nullValue)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if value.Len() == 0 {
|
|
|
|
|
p.state.Write2Byte('[',']')
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tp := value.Type()
|
|
|
|
|
if tp.Elem().Kind() == reflect.Uint8 && p.options.ByteSliceAsBinary() {
|
|
|
|
|
p.PackBinary(value.Bytes())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Comprobamos las llamadas recursivas
|
|
|
|
|
/*
|
|
|
|
|
if p.state.Node.Level > notDetectingCycles {
|
|
|
|
|
rf := value.Interface()
|
|
|
|
|
if _,is := p.checks[rf]; is {
|
|
|
|
|
p.state.SetError(packs.G.ErrRedundantPack)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
p.checks[rf]=struct{}{}
|
|
|
|
|
defer delete(p.checks,rf)
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
switch tp.Elem().Kind() {
|
|
|
|
|
case reflect.String :
|
|
|
|
|
p.buildList(value, func(bl packs.ListPacker, rv reflect.Value){ bl.ItemString(rv.String()) })
|
|
|
|
|
case reflect.Bool :
|
|
|
|
|
p.buildList(value, func(bl packs.ListPacker, rv reflect.Value){ bl.ItemBool (rv.Bool()) })
|
|
|
|
|
case reflect.Uint8 ,
|
|
|
|
|
reflect.Uint16 ,
|
|
|
|
|
reflect.Uint32 ,
|
|
|
|
|
reflect.Uint64 :
|
|
|
|
|
p.buildList(value, func(bl packs.ListPacker, rv reflect.Value){ bl.ItemUInt64(rv.Uint()) })
|
|
|
|
|
case reflect.Int8 ,
|
|
|
|
|
reflect.Int16 ,
|
|
|
|
|
reflect.Int32 ,
|
|
|
|
|
reflect.Int64 :
|
|
|
|
|
p.buildList(value, func(bl packs.ListPacker, rv reflect.Value){ bl.ItemInt64(rv.Int()) })
|
|
|
|
|
case reflect.Float32,
|
|
|
|
|
reflect.Float64:
|
|
|
|
|
p.buildList(value, func(bl packs.ListPacker, rv reflect.Value){ bl.ItemFloat64(rv.Float()) })
|
|
|
|
|
case reflect.Slice :
|
|
|
|
|
p.buildList(value, func(bl packs.ListPacker, rv reflect.Value){
|
|
|
|
|
p.packListReflected(rv) // Llamamos recursivamente a packListReflected para cada elemento del slice
|
|
|
|
|
if p.state.Error != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
case reflect.Map :
|
|
|
|
|
case reflect.Struct :
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Packer) buildList (value reflect.Value, call func(lp packs.ListPacker, rv reflect.Value)) {
|
|
|
|
|
p.PackList(func (lp packs.ListPacker){
|
|
|
|
|
for i:=0; i<value.Len(); i++ {
|
|
|
|
|
call(lp,value.Index(i))
|
|
|
|
|
if p.state.Error != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (p *Packer) packMapReflected (value reflect.Value) {
|
|
|
|
|
//todo
|
|
|
|
|
}
|
|
|
|
|
|