gtsocial-umbx

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

read.go (4563B)


      1 package mp4
      2 
      3 import (
      4 	"errors"
      5 	"fmt"
      6 	"io"
      7 )
      8 
      9 type BoxPath []BoxType
     10 
     11 func (lhs BoxPath) compareWith(rhs BoxPath) (forwardMatch bool, match bool) {
     12 	if len(lhs) > len(rhs) {
     13 		return false, false
     14 	}
     15 	for i := 0; i < len(lhs); i++ {
     16 		if !lhs[i].MatchWith(rhs[i]) {
     17 			return false, false
     18 		}
     19 	}
     20 	if len(lhs) < len(rhs) {
     21 		return true, false
     22 	}
     23 	return false, true
     24 }
     25 
     26 type ReadHandle struct {
     27 	Params      []interface{}
     28 	BoxInfo     BoxInfo
     29 	Path        BoxPath
     30 	ReadPayload func() (box IBox, n uint64, err error)
     31 	ReadData    func(io.Writer) (n uint64, err error)
     32 	Expand      func(params ...interface{}) (vals []interface{}, err error)
     33 }
     34 
     35 type ReadHandler func(handle *ReadHandle) (val interface{}, err error)
     36 
     37 func ReadBoxStructure(r io.ReadSeeker, handler ReadHandler, params ...interface{}) ([]interface{}, error) {
     38 	if _, err := r.Seek(0, io.SeekStart); err != nil {
     39 		return nil, err
     40 	}
     41 	return readBoxStructure(r, 0, true, nil, Context{}, handler, params)
     42 }
     43 
     44 func ReadBoxStructureFromInternal(r io.ReadSeeker, bi *BoxInfo, handler ReadHandler, params ...interface{}) (interface{}, error) {
     45 	return readBoxStructureFromInternal(r, bi, nil, handler, params)
     46 }
     47 
     48 func readBoxStructureFromInternal(r io.ReadSeeker, bi *BoxInfo, path BoxPath, handler ReadHandler, params []interface{}) (interface{}, error) {
     49 	if _, err := bi.SeekToPayload(r); err != nil {
     50 		return nil, err
     51 	}
     52 
     53 	// check comatible-brands
     54 	if len(path) == 0 && bi.Type == BoxTypeFtyp() {
     55 		var ftyp Ftyp
     56 		if _, err := Unmarshal(r, bi.Size-bi.HeaderSize, &ftyp, bi.Context); err != nil {
     57 			return nil, err
     58 		}
     59 		if ftyp.HasCompatibleBrand(BrandQT()) {
     60 			bi.IsQuickTimeCompatible = true
     61 		}
     62 		if _, err := bi.SeekToPayload(r); err != nil {
     63 			return nil, err
     64 		}
     65 	}
     66 
     67 	ctx := bi.Context
     68 	if bi.Type == BoxTypeWave() {
     69 		ctx.UnderWave = true
     70 	} else if bi.Type == BoxTypeIlst() {
     71 		ctx.UnderIlst = true
     72 	} else if bi.UnderIlst && !bi.UnderIlstMeta && IsIlstMetaBoxType(bi.Type) {
     73 		ctx.UnderIlstMeta = true
     74 		if bi.Type == StrToBoxType("----") {
     75 			ctx.UnderIlstFreeMeta = true
     76 		}
     77 	} else if bi.Type == BoxTypeUdta() {
     78 		ctx.UnderUdta = true
     79 	}
     80 
     81 	newPath := make(BoxPath, len(path)+1)
     82 	copy(newPath, path)
     83 	newPath[len(path)] = bi.Type
     84 
     85 	h := &ReadHandle{
     86 		Params:  params,
     87 		BoxInfo: *bi,
     88 		Path:    newPath,
     89 	}
     90 
     91 	var childrenOffset uint64
     92 
     93 	h.ReadPayload = func() (IBox, uint64, error) {
     94 		if _, err := bi.SeekToPayload(r); err != nil {
     95 			return nil, 0, err
     96 		}
     97 
     98 		box, n, err := UnmarshalAny(r, bi.Type, bi.Size-bi.HeaderSize, bi.Context)
     99 		if err != nil {
    100 			return nil, 0, err
    101 		}
    102 		childrenOffset = bi.Offset + bi.HeaderSize + n
    103 		return box, n, nil
    104 	}
    105 
    106 	h.ReadData = func(w io.Writer) (uint64, error) {
    107 		if _, err := bi.SeekToPayload(r); err != nil {
    108 			return 0, err
    109 		}
    110 
    111 		size := bi.Size - bi.HeaderSize
    112 		if _, err := io.CopyN(w, r, int64(size)); err != nil {
    113 			return 0, err
    114 		}
    115 		return size, nil
    116 	}
    117 
    118 	h.Expand = func(params ...interface{}) ([]interface{}, error) {
    119 		if childrenOffset == 0 {
    120 			if _, err := bi.SeekToPayload(r); err != nil {
    121 				return nil, err
    122 			}
    123 
    124 			_, n, err := UnmarshalAny(r, bi.Type, bi.Size-bi.HeaderSize, bi.Context)
    125 			if err != nil {
    126 				return nil, err
    127 			}
    128 			childrenOffset = bi.Offset + bi.HeaderSize + n
    129 		} else {
    130 			if _, err := r.Seek(int64(childrenOffset), io.SeekStart); err != nil {
    131 				return nil, err
    132 			}
    133 		}
    134 
    135 		childrenSize := bi.Offset + bi.Size - childrenOffset
    136 		return readBoxStructure(r, childrenSize, false, newPath, ctx, handler, params)
    137 	}
    138 
    139 	if val, err := handler(h); err != nil {
    140 		return nil, err
    141 	} else if _, err := bi.SeekToEnd(r); err != nil {
    142 		return nil, err
    143 	} else {
    144 		return val, nil
    145 	}
    146 }
    147 
    148 func readBoxStructure(r io.ReadSeeker, totalSize uint64, isRoot bool, path BoxPath, ctx Context, handler ReadHandler, params []interface{}) ([]interface{}, error) {
    149 	vals := make([]interface{}, 0, 8)
    150 
    151 	for isRoot || totalSize >= SmallHeaderSize {
    152 		bi, err := ReadBoxInfo(r)
    153 		if isRoot && err == io.EOF {
    154 			return vals, nil
    155 		} else if err != nil {
    156 			return nil, err
    157 		}
    158 
    159 		if !isRoot && bi.Size > totalSize {
    160 			return nil, fmt.Errorf("too large box size: type=%s, size=%d, actualBufSize=%d", bi.Type.String(), bi.Size, totalSize)
    161 		}
    162 		totalSize -= bi.Size
    163 
    164 		bi.Context = ctx
    165 
    166 		val, err := readBoxStructureFromInternal(r, bi, path, handler, params)
    167 		if err != nil {
    168 			return nil, err
    169 		}
    170 		vals = append(vals, val)
    171 
    172 		if bi.IsQuickTimeCompatible {
    173 			ctx.IsQuickTimeCompatible = true
    174 		}
    175 	}
    176 
    177 	if totalSize != 0 && !ctx.IsQuickTimeCompatible {
    178 		return nil, errors.New("Unexpected EOF")
    179 	}
    180 
    181 	return vals, nil
    182 }