gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

string.go (6029B)


      1 package mp4
      2 
      3 import (
      4 	"bytes"
      5 	"fmt"
      6 	"io"
      7 	"reflect"
      8 	"strconv"
      9 
     10 	"github.com/abema/go-mp4/util"
     11 )
     12 
     13 type stringifier struct {
     14 	buf    *bytes.Buffer
     15 	src    IImmutableBox
     16 	indent string
     17 	ctx    Context
     18 }
     19 
     20 func Stringify(src IImmutableBox, ctx Context) (string, error) {
     21 	return StringifyWithIndent(src, "", ctx)
     22 }
     23 
     24 func StringifyWithIndent(src IImmutableBox, indent string, ctx Context) (string, error) {
     25 	boxDef := src.GetType().getBoxDef(ctx)
     26 	if boxDef == nil {
     27 		return "", ErrBoxInfoNotFound
     28 	}
     29 
     30 	v := reflect.ValueOf(src).Elem()
     31 
     32 	m := &stringifier{
     33 		buf:    bytes.NewBuffer(nil),
     34 		src:    src,
     35 		indent: indent,
     36 		ctx:    ctx,
     37 	}
     38 
     39 	err := m.stringifyStruct(v, boxDef.fields, 0, true)
     40 	if err != nil {
     41 		return "", err
     42 	}
     43 
     44 	return m.buf.String(), nil
     45 }
     46 
     47 func (m *stringifier) stringify(v reflect.Value, fi *fieldInstance, depth int) error {
     48 	switch v.Type().Kind() {
     49 	case reflect.Ptr:
     50 		return m.stringifyPtr(v, fi, depth)
     51 	case reflect.Struct:
     52 		return m.stringifyStruct(v, fi.children, depth, fi.is(fieldExtend))
     53 	case reflect.Array:
     54 		return m.stringifyArray(v, fi, depth)
     55 	case reflect.Slice:
     56 		return m.stringifySlice(v, fi, depth)
     57 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
     58 		return m.stringifyInt(v, fi, depth)
     59 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
     60 		return m.stringifyUint(v, fi, depth)
     61 	case reflect.Bool:
     62 		return m.stringifyBool(v, depth)
     63 	case reflect.String:
     64 		return m.stringifyString(v, depth)
     65 	default:
     66 		return fmt.Errorf("unsupported type: %s", v.Type().Kind())
     67 	}
     68 }
     69 
     70 func (m *stringifier) stringifyPtr(v reflect.Value, fi *fieldInstance, depth int) error {
     71 	return m.stringify(v.Elem(), fi, depth)
     72 }
     73 
     74 func (m *stringifier) stringifyStruct(v reflect.Value, fs []*field, depth int, extended bool) error {
     75 	if !extended {
     76 		m.buf.WriteString("{")
     77 		if m.indent != "" {
     78 			m.buf.WriteString("\n")
     79 		}
     80 		depth++
     81 	}
     82 
     83 	for _, f := range fs {
     84 		fi := resolveFieldInstance(f, m.src, v, m.ctx)
     85 
     86 		if !isTargetField(m.src, fi, m.ctx) {
     87 			continue
     88 		}
     89 
     90 		if f.cnst != "" || f.is(fieldHidden) {
     91 			continue
     92 		}
     93 
     94 		if !f.is(fieldExtend) {
     95 			if m.indent != "" {
     96 				writeIndent(m.buf, m.indent, depth+1)
     97 			} else if m.buf.Len() != 0 && m.buf.Bytes()[m.buf.Len()-1] != '{' {
     98 				m.buf.WriteString(" ")
     99 			}
    100 			m.buf.WriteString(f.name)
    101 			m.buf.WriteString("=")
    102 		}
    103 
    104 		str, ok := fi.cfo.StringifyField(f.name, m.indent, depth+1, m.ctx)
    105 		if ok {
    106 			m.buf.WriteString(str)
    107 			if !f.is(fieldExtend) && m.indent != "" {
    108 				m.buf.WriteString("\n")
    109 			}
    110 			continue
    111 		}
    112 
    113 		if f.name == "Version" {
    114 			m.buf.WriteString(strconv.Itoa(int(m.src.GetVersion())))
    115 		} else if f.name == "Flags" {
    116 			fmt.Fprintf(m.buf, "0x%06x", m.src.GetFlags())
    117 		} else {
    118 			err := m.stringify(v.FieldByName(f.name), fi, depth)
    119 			if err != nil {
    120 				return err
    121 			}
    122 		}
    123 
    124 		if !f.is(fieldExtend) && m.indent != "" {
    125 			m.buf.WriteString("\n")
    126 		}
    127 	}
    128 
    129 	if !extended {
    130 		if m.indent != "" {
    131 			writeIndent(m.buf, m.indent, depth)
    132 		}
    133 		m.buf.WriteString("}")
    134 	}
    135 
    136 	return nil
    137 }
    138 
    139 func (m *stringifier) stringifyArray(v reflect.Value, fi *fieldInstance, depth int) error {
    140 	begin, sep, end := "[", ", ", "]"
    141 	if fi.is(fieldString) || fi.is(fieldISO639_2) {
    142 		begin, sep, end = "\"", "", "\""
    143 	} else if fi.is(fieldUUID) {
    144 		begin, sep, end = "", "", ""
    145 	}
    146 
    147 	m.buf.WriteString(begin)
    148 
    149 	m2 := *m
    150 	if fi.is(fieldString) {
    151 		m2.buf = bytes.NewBuffer(nil)
    152 	}
    153 	size := v.Type().Size()
    154 	for i := 0; i < int(size)/int(v.Type().Elem().Size()); i++ {
    155 		if i != 0 {
    156 			m2.buf.WriteString(sep)
    157 		}
    158 
    159 		if err := m2.stringify(v.Index(i), fi, depth+1); err != nil {
    160 			return err
    161 		}
    162 
    163 		if fi.is(fieldUUID) && (i == 3 || i == 5 || i == 7 || i == 9) {
    164 			m.buf.WriteString("-")
    165 		}
    166 	}
    167 	if fi.is(fieldString) {
    168 		m.buf.WriteString(util.EscapeUnprintables(m2.buf.String()))
    169 	}
    170 
    171 	m.buf.WriteString(end)
    172 
    173 	return nil
    174 }
    175 
    176 func (m *stringifier) stringifySlice(v reflect.Value, fi *fieldInstance, depth int) error {
    177 	begin, sep, end := "[", ", ", "]"
    178 	if fi.is(fieldString) || fi.is(fieldISO639_2) {
    179 		begin, sep, end = "\"", "", "\""
    180 	}
    181 
    182 	m.buf.WriteString(begin)
    183 
    184 	m2 := *m
    185 	if fi.is(fieldString) {
    186 		m2.buf = bytes.NewBuffer(nil)
    187 	}
    188 	for i := 0; i < v.Len(); i++ {
    189 		if fi.length != LengthUnlimited && uint(i) >= fi.length {
    190 			break
    191 		}
    192 
    193 		if i != 0 {
    194 			m2.buf.WriteString(sep)
    195 		}
    196 
    197 		if err := m2.stringify(v.Index(i), fi, depth+1); err != nil {
    198 			return err
    199 		}
    200 	}
    201 	if fi.is(fieldString) {
    202 		m.buf.WriteString(util.EscapeUnprintables(m2.buf.String()))
    203 	}
    204 
    205 	m.buf.WriteString(end)
    206 
    207 	return nil
    208 }
    209 
    210 func (m *stringifier) stringifyInt(v reflect.Value, fi *fieldInstance, depth int) error {
    211 	if fi.is(fieldHex) {
    212 		val := v.Int()
    213 		if val >= 0 {
    214 			m.buf.WriteString("0x")
    215 			m.buf.WriteString(strconv.FormatInt(val, 16))
    216 		} else {
    217 			m.buf.WriteString("-0x")
    218 			m.buf.WriteString(strconv.FormatInt(-val, 16))
    219 		}
    220 	} else {
    221 		m.buf.WriteString(strconv.FormatInt(v.Int(), 10))
    222 	}
    223 	return nil
    224 }
    225 
    226 func (m *stringifier) stringifyUint(v reflect.Value, fi *fieldInstance, depth int) error {
    227 	if fi.is(fieldISO639_2) {
    228 		m.buf.WriteString(string([]byte{byte(v.Uint() + 0x60)}))
    229 	} else if fi.is(fieldUUID) {
    230 		fmt.Fprintf(m.buf, "%02x", v.Uint())
    231 	} else if fi.is(fieldString) {
    232 		m.buf.WriteString(string([]byte{byte(v.Uint())}))
    233 	} else if fi.is(fieldHex) || (!fi.is(fieldDec) && v.Type().Kind() == reflect.Uint8) || v.Type().Kind() == reflect.Uintptr {
    234 		m.buf.WriteString("0x")
    235 		m.buf.WriteString(strconv.FormatUint(v.Uint(), 16))
    236 	} else {
    237 		m.buf.WriteString(strconv.FormatUint(v.Uint(), 10))
    238 	}
    239 
    240 	return nil
    241 }
    242 
    243 func (m *stringifier) stringifyBool(v reflect.Value, depth int) error {
    244 	m.buf.WriteString(strconv.FormatBool(v.Bool()))
    245 
    246 	return nil
    247 }
    248 
    249 func (m *stringifier) stringifyString(v reflect.Value, depth int) error {
    250 	m.buf.WriteString("\"")
    251 	m.buf.WriteString(util.EscapeUnprintables(v.String()))
    252 	m.buf.WriteString("\"")
    253 
    254 	return nil
    255 }
    256 
    257 func writeIndent(w io.Writer, indent string, depth int) {
    258 	for i := 0; i < depth; i++ {
    259 		io.WriteString(w, indent)
    260 	}
    261 }