mirror of
https://github.com/blacktop/ipsw.git
synced 2026-06-07 12:27:36 +00:00
251 lines
4.3 KiB
Go
251 lines
4.3 KiB
Go
package utils
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type parsed struct {
|
|
major string
|
|
minor string
|
|
patch string
|
|
short string
|
|
micro string
|
|
}
|
|
|
|
func DiffVersion(v, w string) (string, error) {
|
|
pv, ok1 := parse(v)
|
|
pw, ok2 := parse(w)
|
|
if !ok1 && !ok2 {
|
|
return "", fmt.Errorf("invalid versions: %q, %q", v, w)
|
|
}
|
|
if !ok1 {
|
|
return "", fmt.Errorf("invalid version: %q", v)
|
|
}
|
|
if !ok2 {
|
|
return "", fmt.Errorf("invalid version: %q", w)
|
|
}
|
|
pvm, err := strconv.Atoi(pv.major)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
pwm, err := strconv.Atoi(pw.major)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
pmdelta := max(pvm-pwm, 0)
|
|
pvn, err := strconv.Atoi(pv.minor)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
pwn, err := strconv.Atoi(pw.minor)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
pndelta := max(pvn-pwn, 0)
|
|
pvp, err := strconv.Atoi(pv.patch)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
pwp, err := strconv.Atoi(pw.patch)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
ppdelta := max(pvp-pwp, 0)
|
|
pvs, err := strconv.Atoi(pv.short)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
pws, err := strconv.Atoi(pw.short)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
psdelta := max(pvs-pws, 0)
|
|
pvc, err := strconv.Atoi(pv.micro)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
pwc, err := strconv.Atoi(pw.micro)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
pcdelta := max(pvc-pwc, 0)
|
|
return fmt.Sprintf("%d.%d.%d.%d.%d", pmdelta, pndelta, ppdelta, psdelta, pcdelta), nil
|
|
}
|
|
|
|
// Compare returns an integer comparing two versions according to
|
|
// semantic version precedence.
|
|
// The result will be 0 if v == w, -1 if v < w, or +1 if v > w.
|
|
//
|
|
// An invalid semantic version string is considered less than a valid one.
|
|
// All invalid semantic version strings compare equal to each other.
|
|
func Compare(v, w string) int {
|
|
pv, ok1 := parse(v)
|
|
pw, ok2 := parse(w)
|
|
if !ok1 && !ok2 {
|
|
return 0
|
|
}
|
|
if !ok1 {
|
|
return -1
|
|
}
|
|
if !ok2 {
|
|
return +1
|
|
}
|
|
if c := compareInt(pv.major, pw.major); c != 0 {
|
|
return c
|
|
}
|
|
if c := compareInt(pv.minor, pw.minor); c != 0 {
|
|
return c
|
|
}
|
|
if c := compareInt(pv.patch, pw.patch); c != 0 {
|
|
return c
|
|
}
|
|
if c := compareInt(pv.short, pw.short); c != 0 {
|
|
return c
|
|
}
|
|
if c := compareInt(pv.micro, pw.micro); c != 0 {
|
|
return c
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// ByVersion implements sort.Interface for sorting semantic version strings.
|
|
type ByVersion []string
|
|
|
|
func (vs ByVersion) Len() int { return len(vs) }
|
|
func (vs ByVersion) Swap(i, j int) { vs[i], vs[j] = vs[j], vs[i] }
|
|
func (vs ByVersion) Less(i, j int) bool {
|
|
cmp := Compare(vs[i], vs[j])
|
|
if cmp != 0 {
|
|
return cmp < 0
|
|
}
|
|
return vs[i] < vs[j]
|
|
}
|
|
|
|
// SortVersions sorts a list of semantic version strings using ByVersion.
|
|
func SortVersions(list []string) {
|
|
sort.Sort(ByVersion(list))
|
|
}
|
|
|
|
type MachoVersion struct {
|
|
Name string
|
|
Version string
|
|
}
|
|
|
|
type ByMachoVersion []MachoVersion
|
|
|
|
func (vs ByMachoVersion) Len() int { return len(vs) }
|
|
func (vs ByMachoVersion) Swap(i, j int) { vs[i], vs[j] = vs[j], vs[i] }
|
|
func (vs ByMachoVersion) Less(i, j int) bool {
|
|
cmp := Compare(vs[i].Version, vs[j].Version)
|
|
if cmp != 0 {
|
|
return cmp > 0
|
|
}
|
|
return strings.Compare(vs[i].Name, vs[j].Name) < 0
|
|
}
|
|
|
|
func SortMachoVersions(list []MachoVersion) {
|
|
sort.Sort(ByMachoVersion(list))
|
|
}
|
|
|
|
func parse(v string) (p parsed, ok bool) {
|
|
p.major, v, ok = parseInt(v)
|
|
if !ok {
|
|
return
|
|
}
|
|
if v == "" {
|
|
p.minor = "0"
|
|
p.patch = "0"
|
|
p.short = ".0.0"
|
|
return
|
|
}
|
|
if v[0] != '.' {
|
|
ok = false
|
|
return
|
|
}
|
|
p.minor, v, ok = parseInt(v[1:])
|
|
if !ok {
|
|
return
|
|
}
|
|
if v == "" {
|
|
p.patch = "0"
|
|
p.short = ".0"
|
|
return
|
|
}
|
|
if v[0] != '.' {
|
|
ok = false
|
|
return
|
|
}
|
|
p.patch, v, ok = parseInt(v[1:])
|
|
if !ok {
|
|
return
|
|
}
|
|
if v == "" {
|
|
p.patch = "0"
|
|
p.short = ".0"
|
|
return
|
|
}
|
|
if v[0] != '.' {
|
|
ok = false
|
|
return
|
|
}
|
|
p.short, v, ok = parseInt(v[1:])
|
|
if !ok {
|
|
return
|
|
}
|
|
if v == "" {
|
|
p.short = ".0"
|
|
return
|
|
}
|
|
if v[0] != '.' {
|
|
ok = false
|
|
return
|
|
}
|
|
p.micro, v, ok = parseInt(v[1:])
|
|
if !ok {
|
|
return
|
|
}
|
|
if v != "" {
|
|
ok = false
|
|
return
|
|
}
|
|
ok = true
|
|
return
|
|
}
|
|
|
|
func parseInt(v string) (t, rest string, ok bool) {
|
|
if v == "" {
|
|
return
|
|
}
|
|
if v[0] < '0' || '9' < v[0] {
|
|
return
|
|
}
|
|
i := 1
|
|
for i < len(v) && '0' <= v[i] && v[i] <= '9' {
|
|
i++
|
|
}
|
|
if v[0] == '0' && i != 1 {
|
|
return
|
|
}
|
|
return v[:i], v[i:], true
|
|
}
|
|
|
|
func compareInt(x, y string) int {
|
|
if x == y {
|
|
return 0
|
|
}
|
|
if len(x) < len(y) {
|
|
return -1
|
|
}
|
|
if len(x) > len(y) {
|
|
return +1
|
|
}
|
|
if x < y {
|
|
return -1
|
|
} else {
|
|
return +1
|
|
}
|
|
}
|