@@ -4,6 +4,9 @@ package mpd
44
55import (
66 "encoding/xml"
7+ "errors"
8+ "strconv"
9+ "strings"
710 "time"
811)
912
@@ -13,6 +16,15 @@ func (d Duration) MarshalXMLAttr(name xml.Name) (xml.Attr, error) {
1316 return xml.Attr {name , d .String ()}, nil
1417}
1518
19+ func (d * Duration ) UnmarshalXMLAttr (attr xml.Attr ) error {
20+ dur , err := parseDuration (attr .Value )
21+ if err != nil {
22+ return err
23+ }
24+ * d = Duration (dur )
25+ return nil
26+ }
27+
1628// String renders a Duration in XML Duration Data Type format
1729func (d * Duration ) String () string {
1830 // Largest time is 2540400h10m10.000000000s
@@ -126,3 +138,80 @@ func fmtInt(buf []byte, v uint64) int {
126138 }
127139 return w
128140}
141+
142+ func parseDuration (str string ) (time.Duration , error ) {
143+ if len (str ) < 3 {
144+ return 0 , errors .New ("input duration too short" )
145+ }
146+
147+ var minus bool
148+ offset := 0
149+ if str [offset ] == '-' {
150+ minus = true
151+ offset ++
152+ }
153+
154+ if str [offset ] != 'P' {
155+ return 0 , errors .New ("input duration does not have a valid prefix" )
156+ }
157+ offset ++
158+
159+ var dateStr , timeStr string
160+ if i := strings .IndexByte (str [offset :], 'T' ); i != - 1 {
161+ dateStr = str [offset : offset + i ]
162+ timeStr = str [offset + i + 1 :]
163+ } else {
164+ dateStr = str [offset :]
165+ }
166+
167+ var sum float64
168+ if len (dateStr ) > 0 {
169+ if i := strings .IndexByte (dateStr , 'Y' ); i != - 1 {
170+ return 0 , errors .New ("input duration contains Years notation" )
171+ }
172+
173+ if i := strings .IndexByte (dateStr , 'M' ); i != - 1 {
174+ return 0 , errors .New ("input duration contains Months notation" )
175+ }
176+
177+ if i := strings .IndexByte (dateStr , 'D' ); i != - 1 {
178+ days , err := strconv .Atoi (dateStr [0 :i ])
179+ if err != nil {
180+ return 0 , err
181+ }
182+ sum += float64 (days ) * 86400
183+ }
184+ }
185+
186+ if len (timeStr ) > 0 {
187+ var pos int
188+ if i := strings .IndexByte (timeStr [pos :], 'H' ); i != - 1 {
189+ hours , err := strconv .ParseInt (timeStr [pos :pos + i ], 10 , 64 )
190+ if err != nil {
191+ return 0 , err
192+ }
193+ sum += float64 (hours ) * 3600
194+ pos += i + 1
195+ }
196+ if i := strings .IndexByte (timeStr [pos :], 'M' ); i != - 1 {
197+ minutes , err := strconv .ParseInt (timeStr [pos :pos + i ], 10 , 64 )
198+ if err != nil {
199+ return 0 , err
200+ }
201+ sum += float64 (minutes ) * 60
202+ pos += i + 1
203+ }
204+ if i := strings .IndexByte (timeStr [pos :], 'S' ); i != - 1 {
205+ seconds , err := strconv .ParseFloat (timeStr [pos :pos + i ], 64 )
206+ if err != nil {
207+ return 0 , err
208+ }
209+ sum += seconds
210+ }
211+ }
212+
213+ if minus {
214+ sum = - sum
215+ }
216+ return time .Duration (sum * float64 (time .Second )), nil
217+ }
0 commit comments