gtsocial-umbx

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

field.go (5697B)


      1 package mp4
      2 
      3 import (
      4 	"fmt"
      5 	"os"
      6 	"reflect"
      7 	"sort"
      8 	"strconv"
      9 	"strings"
     10 )
     11 
     12 type (
     13 	stringType uint8
     14 	fieldFlag  uint16
     15 )
     16 
     17 const (
     18 	stringType_C stringType = iota
     19 	stringType_C_P
     20 
     21 	fieldString        fieldFlag = 1 << iota // 0
     22 	fieldExtend                              // 1
     23 	fieldDec                                 // 2
     24 	fieldHex                                 // 3
     25 	fieldISO639_2                            // 4
     26 	fieldUUID                                // 5
     27 	fieldHidden                              // 6
     28 	fieldOptDynamic                          // 7
     29 	fieldVarint                              // 8
     30 	fieldSizeDynamic                         // 9
     31 	fieldLengthDynamic                       // 10
     32 )
     33 
     34 type field struct {
     35 	children []*field
     36 	name     string
     37 	cnst     string
     38 	order    int
     39 	optFlag  uint32
     40 	nOptFlag uint32
     41 	size     uint
     42 	length   uint
     43 	flags    fieldFlag
     44 	strType  stringType
     45 	version  uint8
     46 	nVersion uint8
     47 }
     48 
     49 func (f *field) set(flag fieldFlag) {
     50 	f.flags |= flag
     51 }
     52 
     53 func (f *field) is(flag fieldFlag) bool {
     54 	return f.flags&flag != 0
     55 }
     56 
     57 func buildFields(box IImmutableBox) []*field {
     58 	t := reflect.TypeOf(box).Elem()
     59 	return buildFieldsStruct(t)
     60 }
     61 
     62 func buildFieldsStruct(t reflect.Type) []*field {
     63 	fs := make([]*field, 0, 8)
     64 	for i := 0; i < t.NumField(); i++ {
     65 		ft := t.Field(i).Type
     66 		tag, ok := t.Field(i).Tag.Lookup("mp4")
     67 		if !ok {
     68 			continue
     69 		}
     70 		f := buildField(t.Field(i).Name, tag)
     71 		f.children = buildFieldsAny(ft)
     72 		fs = append(fs, f)
     73 	}
     74 	sort.SliceStable(fs, func(i, j int) bool {
     75 		return fs[i].order < fs[j].order
     76 	})
     77 	return fs
     78 }
     79 
     80 func buildFieldsAny(t reflect.Type) []*field {
     81 	switch t.Kind() {
     82 	case reflect.Struct:
     83 		return buildFieldsStruct(t)
     84 	case reflect.Ptr, reflect.Array, reflect.Slice:
     85 		return buildFieldsAny(t.Elem())
     86 	default:
     87 		return nil
     88 	}
     89 }
     90 
     91 func buildField(fieldName string, tag string) *field {
     92 	f := &field{
     93 		name: fieldName,
     94 	}
     95 	tagMap := parseFieldTag(tag)
     96 	for key, val := range tagMap {
     97 		if val != "" {
     98 			continue
     99 		}
    100 		if order, err := strconv.Atoi(key); err == nil {
    101 			f.order = order
    102 			break
    103 		}
    104 	}
    105 
    106 	if val, contained := tagMap["string"]; contained {
    107 		f.set(fieldString)
    108 		if val == "c_p" {
    109 			f.strType = stringType_C_P
    110 			fmt.Fprint(os.Stderr, "go-mp4: string=c_p tag is deprecated!! See https://github.com/abema/go-mp4/issues/76\n")
    111 		}
    112 	}
    113 
    114 	if _, contained := tagMap["varint"]; contained {
    115 		f.set(fieldVarint)
    116 	}
    117 
    118 	if val, contained := tagMap["opt"]; contained {
    119 		if val == "dynamic" {
    120 			f.set(fieldOptDynamic)
    121 		} else {
    122 			base := 10
    123 			if strings.HasPrefix(val, "0x") {
    124 				val = val[2:]
    125 				base = 16
    126 			}
    127 			opt, err := strconv.ParseUint(val, base, 32)
    128 			if err != nil {
    129 				panic(err)
    130 			}
    131 			f.optFlag = uint32(opt)
    132 		}
    133 	}
    134 
    135 	if val, contained := tagMap["nopt"]; contained {
    136 		base := 10
    137 		if strings.HasPrefix(val, "0x") {
    138 			val = val[2:]
    139 			base = 16
    140 		}
    141 		nopt, err := strconv.ParseUint(val, base, 32)
    142 		if err != nil {
    143 			panic(err)
    144 		}
    145 		f.nOptFlag = uint32(nopt)
    146 	}
    147 
    148 	if _, contained := tagMap["extend"]; contained {
    149 		f.set(fieldExtend)
    150 	}
    151 
    152 	if _, contained := tagMap["dec"]; contained {
    153 		f.set(fieldDec)
    154 	}
    155 
    156 	if _, contained := tagMap["hex"]; contained {
    157 		f.set(fieldHex)
    158 	}
    159 
    160 	if _, contained := tagMap["iso639-2"]; contained {
    161 		f.set(fieldISO639_2)
    162 	}
    163 
    164 	if _, contained := tagMap["uuid"]; contained {
    165 		f.set(fieldUUID)
    166 	}
    167 
    168 	if _, contained := tagMap["hidden"]; contained {
    169 		f.set(fieldHidden)
    170 	}
    171 
    172 	if val, contained := tagMap["const"]; contained {
    173 		f.cnst = val
    174 	}
    175 
    176 	f.version = anyVersion
    177 	if val, contained := tagMap["ver"]; contained {
    178 		ver, err := strconv.Atoi(val)
    179 		if err != nil {
    180 			panic(err)
    181 		}
    182 		f.version = uint8(ver)
    183 	}
    184 
    185 	f.nVersion = anyVersion
    186 	if val, contained := tagMap["nver"]; contained {
    187 		ver, err := strconv.Atoi(val)
    188 		if err != nil {
    189 			panic(err)
    190 		}
    191 		f.nVersion = uint8(ver)
    192 	}
    193 
    194 	if val, contained := tagMap["size"]; contained {
    195 		if val == "dynamic" {
    196 			f.set(fieldSizeDynamic)
    197 		} else {
    198 			size, err := strconv.ParseUint(val, 10, 32)
    199 			if err != nil {
    200 				panic(err)
    201 			}
    202 			f.size = uint(size)
    203 		}
    204 	}
    205 
    206 	f.length = LengthUnlimited
    207 	if val, contained := tagMap["len"]; contained {
    208 		if val == "dynamic" {
    209 			f.set(fieldLengthDynamic)
    210 		} else {
    211 			l, err := strconv.ParseUint(val, 10, 32)
    212 			if err != nil {
    213 				panic(err)
    214 			}
    215 			f.length = uint(l)
    216 		}
    217 	}
    218 
    219 	return f
    220 }
    221 
    222 func parseFieldTag(str string) map[string]string {
    223 	tag := make(map[string]string, 8)
    224 
    225 	list := strings.Split(str, ",")
    226 	for _, e := range list {
    227 		kv := strings.SplitN(e, "=", 2)
    228 		if len(kv) == 2 {
    229 			tag[strings.Trim(kv[0], " ")] = strings.Trim(kv[1], " ")
    230 		} else {
    231 			tag[strings.Trim(kv[0], " ")] = ""
    232 		}
    233 	}
    234 
    235 	return tag
    236 }
    237 
    238 type fieldInstance struct {
    239 	field
    240 	cfo ICustomFieldObject
    241 }
    242 
    243 func resolveFieldInstance(f *field, box IImmutableBox, parent reflect.Value, ctx Context) *fieldInstance {
    244 	fi := fieldInstance{
    245 		field: *f,
    246 	}
    247 
    248 	cfo, ok := parent.Addr().Interface().(ICustomFieldObject)
    249 	if ok {
    250 		fi.cfo = cfo
    251 	} else {
    252 		fi.cfo = box
    253 	}
    254 
    255 	if fi.is(fieldSizeDynamic) {
    256 		fi.size = fi.cfo.GetFieldSize(f.name, ctx)
    257 	}
    258 
    259 	if fi.is(fieldLengthDynamic) {
    260 		fi.length = fi.cfo.GetFieldLength(f.name, ctx)
    261 	}
    262 
    263 	return &fi
    264 }
    265 
    266 func isTargetField(box IImmutableBox, fi *fieldInstance, ctx Context) bool {
    267 	if box.GetVersion() != anyVersion {
    268 		if fi.version != anyVersion && box.GetVersion() != fi.version {
    269 			return false
    270 		}
    271 
    272 		if fi.nVersion != anyVersion && box.GetVersion() == fi.nVersion {
    273 			return false
    274 		}
    275 	}
    276 
    277 	if fi.optFlag != 0 && box.GetFlags()&fi.optFlag == 0 {
    278 		return false
    279 	}
    280 
    281 	if fi.nOptFlag != 0 && box.GetFlags()&fi.nOptFlag != 0 {
    282 		return false
    283 	}
    284 
    285 	if fi.is(fieldOptDynamic) && !fi.cfo.IsOptFieldEnabled(fi.name, ctx) {
    286 		return false
    287 	}
    288 
    289 	return true
    290 }