mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 08:22:27 -05:00 
			
		
		
		
	* [feature] basic video support * fix missing semicolon * replace text shadow with stacked icons Co-authored-by: f0x <f0x@cthu.lu>
		
			
				
	
	
		
			261 lines
		
	
	
	
		
			5.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			261 lines
		
	
	
	
		
			5.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package mp4
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"reflect"
 | |
| 	"strconv"
 | |
| 
 | |
| 	"github.com/abema/go-mp4/util"
 | |
| )
 | |
| 
 | |
| type stringifier struct {
 | |
| 	buf    *bytes.Buffer
 | |
| 	src    IImmutableBox
 | |
| 	indent string
 | |
| 	ctx    Context
 | |
| }
 | |
| 
 | |
| func Stringify(src IImmutableBox, ctx Context) (string, error) {
 | |
| 	return StringifyWithIndent(src, "", ctx)
 | |
| }
 | |
| 
 | |
| func StringifyWithIndent(src IImmutableBox, indent string, ctx Context) (string, error) {
 | |
| 	boxDef := src.GetType().getBoxDef(ctx)
 | |
| 	if boxDef == nil {
 | |
| 		return "", ErrBoxInfoNotFound
 | |
| 	}
 | |
| 
 | |
| 	v := reflect.ValueOf(src).Elem()
 | |
| 
 | |
| 	m := &stringifier{
 | |
| 		buf:    bytes.NewBuffer(nil),
 | |
| 		src:    src,
 | |
| 		indent: indent,
 | |
| 		ctx:    ctx,
 | |
| 	}
 | |
| 
 | |
| 	err := m.stringifyStruct(v, boxDef.fields, 0, true)
 | |
| 	if err != nil {
 | |
| 		return "", err
 | |
| 	}
 | |
| 
 | |
| 	return m.buf.String(), nil
 | |
| }
 | |
| 
 | |
| func (m *stringifier) stringify(v reflect.Value, fi *fieldInstance, depth int) error {
 | |
| 	switch v.Type().Kind() {
 | |
| 	case reflect.Ptr:
 | |
| 		return m.stringifyPtr(v, fi, depth)
 | |
| 	case reflect.Struct:
 | |
| 		return m.stringifyStruct(v, fi.children, depth, fi.is(fieldExtend))
 | |
| 	case reflect.Array:
 | |
| 		return m.stringifyArray(v, fi, depth)
 | |
| 	case reflect.Slice:
 | |
| 		return m.stringifySlice(v, fi, depth)
 | |
| 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | |
| 		return m.stringifyInt(v, fi, depth)
 | |
| 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
 | |
| 		return m.stringifyUint(v, fi, depth)
 | |
| 	case reflect.Bool:
 | |
| 		return m.stringifyBool(v, depth)
 | |
| 	case reflect.String:
 | |
| 		return m.stringifyString(v, depth)
 | |
| 	default:
 | |
| 		return fmt.Errorf("unsupported type: %s", v.Type().Kind())
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (m *stringifier) stringifyPtr(v reflect.Value, fi *fieldInstance, depth int) error {
 | |
| 	return m.stringify(v.Elem(), fi, depth)
 | |
| }
 | |
| 
 | |
| func (m *stringifier) stringifyStruct(v reflect.Value, fs []*field, depth int, extended bool) error {
 | |
| 	if !extended {
 | |
| 		m.buf.WriteString("{")
 | |
| 		if m.indent != "" {
 | |
| 			m.buf.WriteString("\n")
 | |
| 		}
 | |
| 		depth++
 | |
| 	}
 | |
| 
 | |
| 	for _, f := range fs {
 | |
| 		fi := resolveFieldInstance(f, m.src, v, m.ctx)
 | |
| 
 | |
| 		if !isTargetField(m.src, fi, m.ctx) {
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		if f.cnst != "" || f.is(fieldHidden) {
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		if !f.is(fieldExtend) {
 | |
| 			if m.indent != "" {
 | |
| 				writeIndent(m.buf, m.indent, depth+1)
 | |
| 			} else if m.buf.Len() != 0 && m.buf.Bytes()[m.buf.Len()-1] != '{' {
 | |
| 				m.buf.WriteString(" ")
 | |
| 			}
 | |
| 			m.buf.WriteString(f.name)
 | |
| 			m.buf.WriteString("=")
 | |
| 		}
 | |
| 
 | |
| 		str, ok := fi.cfo.StringifyField(f.name, m.indent, depth+1, m.ctx)
 | |
| 		if ok {
 | |
| 			m.buf.WriteString(str)
 | |
| 			if !f.is(fieldExtend) && m.indent != "" {
 | |
| 				m.buf.WriteString("\n")
 | |
| 			}
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		if f.name == "Version" {
 | |
| 			m.buf.WriteString(strconv.Itoa(int(m.src.GetVersion())))
 | |
| 		} else if f.name == "Flags" {
 | |
| 			fmt.Fprintf(m.buf, "0x%06x", m.src.GetFlags())
 | |
| 		} else {
 | |
| 			err := m.stringify(v.FieldByName(f.name), fi, depth)
 | |
| 			if err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if !f.is(fieldExtend) && m.indent != "" {
 | |
| 			m.buf.WriteString("\n")
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if !extended {
 | |
| 		if m.indent != "" {
 | |
| 			writeIndent(m.buf, m.indent, depth)
 | |
| 		}
 | |
| 		m.buf.WriteString("}")
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (m *stringifier) stringifyArray(v reflect.Value, fi *fieldInstance, depth int) error {
 | |
| 	begin, sep, end := "[", ", ", "]"
 | |
| 	if fi.is(fieldString) || fi.is(fieldISO639_2) {
 | |
| 		begin, sep, end = "\"", "", "\""
 | |
| 	} else if fi.is(fieldUUID) {
 | |
| 		begin, sep, end = "", "", ""
 | |
| 	}
 | |
| 
 | |
| 	m.buf.WriteString(begin)
 | |
| 
 | |
| 	m2 := *m
 | |
| 	if fi.is(fieldString) {
 | |
| 		m2.buf = bytes.NewBuffer(nil)
 | |
| 	}
 | |
| 	size := v.Type().Size()
 | |
| 	for i := 0; i < int(size)/int(v.Type().Elem().Size()); i++ {
 | |
| 		if i != 0 {
 | |
| 			m2.buf.WriteString(sep)
 | |
| 		}
 | |
| 
 | |
| 		if err := m2.stringify(v.Index(i), fi, depth+1); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 
 | |
| 		if fi.is(fieldUUID) && (i == 3 || i == 5 || i == 7 || i == 9) {
 | |
| 			m.buf.WriteString("-")
 | |
| 		}
 | |
| 	}
 | |
| 	if fi.is(fieldString) {
 | |
| 		m.buf.WriteString(util.EscapeUnprintables(m2.buf.String()))
 | |
| 	}
 | |
| 
 | |
| 	m.buf.WriteString(end)
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (m *stringifier) stringifySlice(v reflect.Value, fi *fieldInstance, depth int) error {
 | |
| 	begin, sep, end := "[", ", ", "]"
 | |
| 	if fi.is(fieldString) || fi.is(fieldISO639_2) {
 | |
| 		begin, sep, end = "\"", "", "\""
 | |
| 	}
 | |
| 
 | |
| 	m.buf.WriteString(begin)
 | |
| 
 | |
| 	m2 := *m
 | |
| 	if fi.is(fieldString) {
 | |
| 		m2.buf = bytes.NewBuffer(nil)
 | |
| 	}
 | |
| 	for i := 0; i < v.Len(); i++ {
 | |
| 		if fi.length != LengthUnlimited && uint(i) >= fi.length {
 | |
| 			break
 | |
| 		}
 | |
| 
 | |
| 		if i != 0 {
 | |
| 			m2.buf.WriteString(sep)
 | |
| 		}
 | |
| 
 | |
| 		if err := m2.stringify(v.Index(i), fi, depth+1); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 	if fi.is(fieldString) {
 | |
| 		m.buf.WriteString(util.EscapeUnprintables(m2.buf.String()))
 | |
| 	}
 | |
| 
 | |
| 	m.buf.WriteString(end)
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (m *stringifier) stringifyInt(v reflect.Value, fi *fieldInstance, depth int) error {
 | |
| 	if fi.is(fieldHex) {
 | |
| 		val := v.Int()
 | |
| 		if val >= 0 {
 | |
| 			m.buf.WriteString("0x")
 | |
| 			m.buf.WriteString(strconv.FormatInt(val, 16))
 | |
| 		} else {
 | |
| 			m.buf.WriteString("-0x")
 | |
| 			m.buf.WriteString(strconv.FormatInt(-val, 16))
 | |
| 		}
 | |
| 	} else {
 | |
| 		m.buf.WriteString(strconv.FormatInt(v.Int(), 10))
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (m *stringifier) stringifyUint(v reflect.Value, fi *fieldInstance, depth int) error {
 | |
| 	if fi.is(fieldISO639_2) {
 | |
| 		m.buf.WriteString(string([]byte{byte(v.Uint() + 0x60)}))
 | |
| 	} else if fi.is(fieldUUID) {
 | |
| 		fmt.Fprintf(m.buf, "%02x", v.Uint())
 | |
| 	} else if fi.is(fieldString) {
 | |
| 		m.buf.WriteString(string([]byte{byte(v.Uint())}))
 | |
| 	} else if fi.is(fieldHex) || (!fi.is(fieldDec) && v.Type().Kind() == reflect.Uint8) || v.Type().Kind() == reflect.Uintptr {
 | |
| 		m.buf.WriteString("0x")
 | |
| 		m.buf.WriteString(strconv.FormatUint(v.Uint(), 16))
 | |
| 	} else {
 | |
| 		m.buf.WriteString(strconv.FormatUint(v.Uint(), 10))
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (m *stringifier) stringifyBool(v reflect.Value, depth int) error {
 | |
| 	m.buf.WriteString(strconv.FormatBool(v.Bool()))
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (m *stringifier) stringifyString(v reflect.Value, depth int) error {
 | |
| 	m.buf.WriteString("\"")
 | |
| 	m.buf.WriteString(util.EscapeUnprintables(v.String()))
 | |
| 	m.buf.WriteString("\"")
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func writeIndent(w io.Writer, indent string, depth int) {
 | |
| 	for i := 0; i < depth; i++ {
 | |
| 		io.WriteString(w, indent)
 | |
| 	}
 | |
| }
 |