Initial QSfera import
This commit is contained in:
+128
@@ -0,0 +1,128 @@
|
||||
package saml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Duration is a time.Duration that uses the xsd:duration format for text
|
||||
// marshalling and unmarshalling.
|
||||
type Duration time.Duration
|
||||
|
||||
// MarshalText implements the encoding.TextMarshaler interface.
|
||||
func (d Duration) MarshalText() ([]byte, error) {
|
||||
if d == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
out := "PT"
|
||||
if d < 0 {
|
||||
d *= -1
|
||||
out = "-" + out
|
||||
}
|
||||
|
||||
h := time.Duration(d) / time.Hour
|
||||
m := time.Duration(d) % time.Hour / time.Minute
|
||||
s := time.Duration(d) % time.Minute / time.Second
|
||||
ns := time.Duration(d) % time.Second
|
||||
if h > 0 {
|
||||
out += fmt.Sprintf("%dH", h)
|
||||
}
|
||||
if m > 0 {
|
||||
out += fmt.Sprintf("%dM", m)
|
||||
}
|
||||
if s > 0 || ns > 0 {
|
||||
out += fmt.Sprintf("%d", s)
|
||||
if ns > 0 {
|
||||
out += strings.TrimRight(fmt.Sprintf(".%09d", ns), "0")
|
||||
}
|
||||
out += "S"
|
||||
}
|
||||
|
||||
return []byte(out), nil
|
||||
}
|
||||
|
||||
const (
|
||||
day = 24 * time.Hour
|
||||
month = 30 * day // Assumed to be 30 days.
|
||||
year = 365 * day // Assumed to be non-leap year.
|
||||
)
|
||||
|
||||
var (
|
||||
durationRegexp = regexp.MustCompile(`^(-?)P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(.+))?$`)
|
||||
durationTimeRegexp = regexp.MustCompile(`^(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?$`)
|
||||
)
|
||||
|
||||
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||
func (d *Duration) UnmarshalText(text []byte) error {
|
||||
if text == nil {
|
||||
*d = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
out time.Duration
|
||||
sign time.Duration = 1
|
||||
)
|
||||
match := durationRegexp.FindStringSubmatch(string(text))
|
||||
if match == nil || strings.Join(match[2:6], "") == "" {
|
||||
return fmt.Errorf("invalid duration (%s)", text)
|
||||
}
|
||||
if match[1] == "-" {
|
||||
sign = -1
|
||||
}
|
||||
if match[2] != "" {
|
||||
y, err := strconv.Atoi(match[2])
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid duration years (%s): %s", text, err)
|
||||
}
|
||||
out += time.Duration(y) * year
|
||||
}
|
||||
if match[3] != "" {
|
||||
m, err := strconv.Atoi(match[3])
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid duration months (%s): %s", text, err)
|
||||
}
|
||||
out += time.Duration(m) * month
|
||||
}
|
||||
if match[4] != "" {
|
||||
d, err := strconv.Atoi(match[4])
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid duration days (%s): %s", text, err)
|
||||
}
|
||||
out += time.Duration(d) * day
|
||||
}
|
||||
if match[5] != "" {
|
||||
match := durationTimeRegexp.FindStringSubmatch(match[5])
|
||||
if match == nil {
|
||||
return fmt.Errorf("invalid duration (%s)", text)
|
||||
}
|
||||
if match[1] != "" {
|
||||
h, err := strconv.Atoi(match[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid duration hours (%s): %s", text, err)
|
||||
}
|
||||
out += time.Duration(h) * time.Hour
|
||||
}
|
||||
if match[2] != "" {
|
||||
m, err := strconv.Atoi(match[2])
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid duration minutes (%s): %s", text, err)
|
||||
}
|
||||
out += time.Duration(m) * time.Minute
|
||||
}
|
||||
if match[3] != "" {
|
||||
s, err := strconv.ParseFloat(match[3], 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid duration seconds (%s): %s", text, err)
|
||||
}
|
||||
out += time.Duration(s * float64(time.Second))
|
||||
}
|
||||
}
|
||||
|
||||
*d = Duration(sign * out)
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user