Skip to content

Commit

Permalink
golang codec
Browse files Browse the repository at this point in the history
golang bytes to struct and struct to bytes
  • Loading branch information
dxhbiz committed Apr 16, 2016
0 parents commit 0aa1eeb
Show file tree
Hide file tree
Showing 4 changed files with 407 additions and 0 deletions.
22 changes: 22 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Auto detect text files and perform LF normalization
* text=auto

# Custom for Visual Studio
*.cs diff=csharp
*.sln merge=union
*.csproj merge=union
*.vbproj merge=union
*.fsproj merge=union
*.dbproj merge=union

# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain
63 changes: 63 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so

# Folders
_obj
_test

# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out

*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*

_testmain.go

*.exe
*.test

# =========================
# Operating System Files
# =========================

# OSX
# =========================

.DS_Store
.AppleDouble
.LSOverride

# Icon must ends with two \r.
Icon

# Thumbnails
._*

# Files that might appear on external disk
.Spotlight-V100
.Trashes

# Windows
# =========================

# Windows image file caches
Thumbs.db
ehthumbs.db

# Folder config file
Desktop.ini

# Recycle Bin used on file shares
$RECYCLE.BIN/

# Windows Installer files
*.cab
*.msi
*.msm
*.msp
Expand Down
166 changes: 166 additions & 0 deletions codec/decode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
package codec

import (
"bytes"
"runtime"
"reflect"
"fmt"
"encoding/binary"
)

func Decode(data []byte, v interface {}) error {
de := new(decoder)
de.buf = bytes.NewBuffer(data)
if err := de.unmarshal(v); err != nil {
return err
}
return nil
}

type decoder struct {
buf *bytes.Buffer
}

func (this *decoder) unmarshal(v interface {}) (err error) {
defer func() {
if r := recover(); r != nil {
if _, ok := r.(runtime.Error); ok {
panic(r)
}
if s, ok := r.(string); ok {
panic(s)
}
err = r.(error)
}
}()
this.reflect(v)
return nil
}

func (this *decoder) reflect(v interface {}) {
if reflect.TypeOf(v).Kind() != reflect.Ptr {
this.error(fmt.Errorf("Interface's kind must be reflect.Ptr."))
}
rv := reflect.ValueOf(v).Elem()
if !rv.CanSet() {
this.error(fmt.Errorf("Reflect value can't set."))
}
rvCount := rv.NumField()
for i := 0; i < rvCount; i++ {
this.decode(rv.Field(i))
}
}

func (this *decoder) decode(rv reflect.Value) {
switch rv.Kind() {
case reflect.Array:
this.decodeArray(rv)
case reflect.Slice:
this.decodeSlice(rv)
case reflect.Struct:
this.decodeStruct(rv)
case reflect.String:
this.decodeString(rv)
default:
this.decodeValue(rv)
}
}

func (this *decoder) decodeArray(rv reflect.Value) {
rvLen := rv.Len()
if rvLen <= 0 {
return
}

firstElem := rv.Index(0)
switch firstElem.Kind() {
case reflect.Uint8:
valArr := this.buf.Next(rvLen)
reflect.Copy(rv, reflect.ValueOf(valArr))
case reflect.Struct:
for i := 0; i < rvLen; i++ {
this.decodeStruct(rv.Index(i))
}
case reflect.String:
this.decodeString(rv)
}
}

func (this *decoder) decodeSlice(rv reflect.Value) {
var rvLen uint32
binary.Read(this.buf, binary.LittleEndian, &rvLen)

if rvLen <= 0 {
return
}

newRv := reflect.MakeSlice(rv.Type(), int(rvLen), int(rvLen))
rv.Set(newRv)
this.decodeArray(rv)
}

func (this *decoder) decodeStruct(rv reflect.Value) {
rvCount := rv.NumField()
for i := 0; i < rvCount; i++ {
this.decode(rv.Field(i))
}
}

func (this *decoder) decodeString(rv reflect.Value) {
var rvLen uint32
binary.Read(this.buf, binary.LittleEndian, &rvLen)
if rvLen <= 0 {
return
}
strBytes := this.buf.Next(int(rvLen))
rv.SetString(string(strBytes))
}

func (this *decoder) decodeValue(rv reflect.Value) {
switch rv.Kind() {
case reflect.Bool:
var val uint8
binary.Read(this.buf, binary.LittleEndian, &val)
if val > 0 {
rv.SetBool(true)
}
case reflect.Uint8:
var val uint8
binary.Read(this.buf, binary.LittleEndian, &val)
rv.SetUint(uint64(val))
case reflect.Int16:
var val int16
binary.Read(this.buf, binary.LittleEndian, &val)
rv.SetInt(int64(val))
case reflect.Uint16:
var val uint16
binary.Read(this.buf, binary.LittleEndian, &val)
rv.SetUint(uint64(val))
case reflect.Int32:
var val int32
binary.Read(this.buf, binary.LittleEndian, &val)
rv.SetInt(int64(val))
case reflect.Uint32:
var val uint32
binary.Read(this.buf, binary.LittleEndian, &val)
rv.SetUint(uint64(val))
case reflect.Float32:
var val float32
binary.Read(this.buf, binary.LittleEndian, &val)
rv.SetFloat(float64(val))
case reflect.Int64:
var val int64
binary.Read(this.buf, binary.LittleEndian, &val)
rv.SetInt(val)
case reflect.Uint64:
var val uint64
binary.Read(this.buf, binary.LittleEndian, &val)
rv.SetUint(val)
default:
this.error(fmt.Errorf("Can't decode %v type", rv.Kind()))
}
}

func (this *decoder) error(err error) {
panic(err)
}
Loading

0 comments on commit 0aa1eeb

Please sign in to comment.