add support for Open Connectivity Foundation DCPs
This commit is contained in:
		@@ -2,15 +2,21 @@ package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"html/template"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var packageTmpl = template.Must(template.New("package").Parse(`{{$name := .Metadata.Name}}
 | 
			
		||||
var templateFuncs = template.FuncMap{
 | 
			
		||||
	"base": filepath.Base,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var packageTmpl = template.Must(template.New("package").Funcs(templateFuncs).Parse(`{{$name := .Metadata.Name}}
 | 
			
		||||
// Client for UPnP Device Control Protocol {{.Metadata.OfficialName}}.
 | 
			
		||||
// {{if .Metadata.DocURL}}
 | 
			
		||||
// This DCP is documented in detail at: {{.Metadata.DocURL}}{{end}}
 | 
			
		||||
// {{if .DocURLs}}
 | 
			
		||||
// This DCP is documented in detail at: {{range .DocURLs}}
 | 
			
		||||
// - {{.}}{{end}}{{end}}
 | 
			
		||||
//
 | 
			
		||||
// Typically, use one of the New* functions to create clients for services.
 | 
			
		||||
package {{$name}}
 | 
			
		||||
package {{$name | base}}
 | 
			
		||||
 | 
			
		||||
// ***********************************************************
 | 
			
		||||
// GENERATED FILE - DO NOT EDIT BY HAND. See README.md
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,7 @@ import (
 | 
			
		||||
// DCP collects together information about a UPnP Device Control Protocol.
 | 
			
		||||
type DCP struct {
 | 
			
		||||
	Metadata     DCPMetadata
 | 
			
		||||
	DocURLs      []string
 | 
			
		||||
	DeviceTypes  map[string]*URNParts
 | 
			
		||||
	ServiceTypes map[string]*URNParts
 | 
			
		||||
	Services     []SCPDWithURN
 | 
			
		||||
@@ -29,22 +30,33 @@ func newDCP(metadata DCPMetadata) *DCP {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (dcp *DCP) processZipFile(filename string) error {
 | 
			
		||||
	archive, err := zip.OpenReader(filename)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("error reading zip file %q: %v", filename, err)
 | 
			
		||||
	}
 | 
			
		||||
	defer archive.Close()
 | 
			
		||||
	for _, deviceFile := range globFiles("*/device/*.xml", archive) {
 | 
			
		||||
		if err := dcp.processDeviceFile(deviceFile); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
func (dcp *DCP) Reset() {
 | 
			
		||||
	dcp.DocURLs = nil
 | 
			
		||||
	dcp.DeviceTypes = make(map[string]*URNParts)
 | 
			
		||||
	dcp.ServiceTypes = make(map[string]*URNParts)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (dcp *DCP) processZipFile(archive []*zip.File, devices, services []string) error {
 | 
			
		||||
	var f int
 | 
			
		||||
	for _, devicesGlob := range devices {
 | 
			
		||||
		for _, deviceFile := range globFiles(devicesGlob, archive) {
 | 
			
		||||
			if err := dcp.processDeviceFile(deviceFile); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			f++
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, scpdFile := range globFiles("*/service/*.xml", archive) {
 | 
			
		||||
		if err := dcp.processSCPDFile(scpdFile); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
	for _, scpdsGlob := range services {
 | 
			
		||||
		for _, scpdFile := range globFiles(scpdsGlob, archive) {
 | 
			
		||||
			if err := dcp.processSCPDFile(scpdFile); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			f++
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if f < 1 {
 | 
			
		||||
		return fmt.Errorf("no sdcp/device found in %q and %q", devices, services)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,24 +9,22 @@ import (
 | 
			
		||||
	"os"
 | 
			
		||||
	"path"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func acquireFile(specFilename string, xmlSpecURL string) error {
 | 
			
		||||
	if f, err := os.Open(specFilename); err != nil {
 | 
			
		||||
		if !os.IsNotExist(err) {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		f.Close()
 | 
			
		||||
	tmpFilename := specFilename + ".download"
 | 
			
		||||
	defer os.Remove(tmpFilename)
 | 
			
		||||
 | 
			
		||||
	if fileExists(specFilename) {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tmpFilename := specFilename + ".download"
 | 
			
		||||
	if err := downloadFile(tmpFilename, xmlSpecURL); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return os.Rename(tmpFilename, specFilename)
 | 
			
		||||
	return copyFile(specFilename, tmpFilename)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func downloadFile(filename, url string) error {
 | 
			
		||||
@@ -54,10 +52,11 @@ func downloadFile(filename, url string) error {
 | 
			
		||||
	return w.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func globFiles(pattern string, archive *zip.ReadCloser) []*zip.File {
 | 
			
		||||
func globFiles(pattern string, archive []*zip.File) []*zip.File {
 | 
			
		||||
	var files []*zip.File
 | 
			
		||||
	for _, f := range archive.File {
 | 
			
		||||
		if matched, err := path.Match(pattern, f.Name); err != nil {
 | 
			
		||||
	pattern = strings.ToLower(pattern)
 | 
			
		||||
	for _, f := range archive {
 | 
			
		||||
		if matched, err := path.Match(pattern, strings.ToLower(f.Name)); err != nil {
 | 
			
		||||
			// This shouldn't happen - all patterns are hard-coded, errors in them
 | 
			
		||||
			// are a programming error.
 | 
			
		||||
			panic(err)
 | 
			
		||||
@@ -93,3 +92,30 @@ func urnPartsFromSCPDFilename(filename string) (*URNParts, error) {
 | 
			
		||||
		Version: version,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyFile(dst string, src string) error {
 | 
			
		||||
	f, err := os.Open(src)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return writeFile(dst, f)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func writeFile(dst string, r io.ReadCloser) error {
 | 
			
		||||
	defer r.Close()
 | 
			
		||||
	f, err := os.Create(dst)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	_, err = io.Copy(f, r)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func fileExists(p string) bool {
 | 
			
		||||
	f, err := os.Open(p)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return !os.IsNotExist(err)
 | 
			
		||||
	}
 | 
			
		||||
	f.Close()
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -35,25 +35,19 @@ func run(dcpName, specsDir string, useGofmt bool) error {
 | 
			
		||||
		return fmt.Errorf("could not create specs-dir %q: %v", specsDir, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, d := range dcpMetadata {
 | 
			
		||||
		if d.Name != dcpName {
 | 
			
		||||
	for _, metadata := range dcpMetadata {
 | 
			
		||||
		if metadata.Name != dcpName {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		specFilename := filepath.Join(specsDir, d.Name+".zip")
 | 
			
		||||
		err := acquireFile(specFilename, d.XMLSpecURL)
 | 
			
		||||
 | 
			
		||||
		dcp := newDCP(metadata)
 | 
			
		||||
 | 
			
		||||
		err := metadata.Src.process(".", metadata.Name, dcp)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fmt.Errorf("could not acquire spec for %s: %v", d.Name, err)
 | 
			
		||||
			return fmt.Errorf("error processing spec %s: %v", metadata.Name, err)
 | 
			
		||||
		}
 | 
			
		||||
		dcp := newDCP(d)
 | 
			
		||||
		if err := dcp.processZipFile(specFilename); err != nil {
 | 
			
		||||
			return fmt.Errorf("error processing spec for %s in file %q: %v", d.Name, specFilename, err)
 | 
			
		||||
		}
 | 
			
		||||
		for i, hack := range d.Hacks {
 | 
			
		||||
			if err := hack(dcp); err != nil {
 | 
			
		||||
				return fmt.Errorf("error with Hack[%d] for %s: %v", i, d.Name, err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if err := dcp.writeCode(d.Name+".go", useGofmt); err != nil {
 | 
			
		||||
 | 
			
		||||
		if err := dcp.writeCode(filepath.Base(metadata.Name)+".go", useGofmt); err != nil {
 | 
			
		||||
			return fmt.Errorf("error writing package %q: %v", dcp.Metadata.Name, err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,69 +1,127 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// DCP contains extra metadata to use when generating DCP source files.
 | 
			
		||||
type DCPMetadata struct {
 | 
			
		||||
	Name         string // What to name the Go DCP package.
 | 
			
		||||
	OfficialName string // Official name for the DCP.
 | 
			
		||||
	DocURL       string // Optional - URL for further documentation about the DCP.
 | 
			
		||||
	XMLSpecURL   string // Where to download the XML spec from.
 | 
			
		||||
	// Any special-case functions to run against the DCP before writing it out.
 | 
			
		||||
	Hacks []DCPHackFn
 | 
			
		||||
	Src          dcpProvider
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var dcpMetadata = []DCPMetadata{
 | 
			
		||||
	{
 | 
			
		||||
		Name:         "internetgateway1",
 | 
			
		||||
		OfficialName: "Internet Gateway Device v1",
 | 
			
		||||
		DocURL:       "http://upnp.org/specs/gw/UPnP-gw-InternetGatewayDevice-v1-Device.pdf",
 | 
			
		||||
		XMLSpecURL:   "http://upnp.org/specs/gw/UPnP-gw-IGD-TestFiles-20010921.zip",
 | 
			
		||||
		Hacks:        []DCPHackFn{totalBytesHack},
 | 
			
		||||
		Src: upnpdotorg{
 | 
			
		||||
			DocURL:     "http://upnp.org/specs/gw/UPnP-gw-InternetGatewayDevice-v1-Device.pdf",
 | 
			
		||||
			XMLSpecURL: "http://upnp.org/specs/gw/UPnP-gw-IGD-TestFiles-20010921.zip",
 | 
			
		||||
			Hacks: []DCPHackFn{
 | 
			
		||||
				fixTotalBytes("urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1"),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:         "internetgateway2",
 | 
			
		||||
		OfficialName: "Internet Gateway Device v2",
 | 
			
		||||
		DocURL:       "http://upnp.org/specs/gw/UPnP-gw-InternetGatewayDevice-v2-Device.pdf",
 | 
			
		||||
		XMLSpecURL:   "http://upnp.org/specs/gw/UPnP-gw-IGD-Testfiles-20110224.zip",
 | 
			
		||||
		Hacks: []DCPHackFn{
 | 
			
		||||
			func(dcp *DCP) error {
 | 
			
		||||
				missingURN := "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1"
 | 
			
		||||
				if _, ok := dcp.ServiceTypes[missingURN]; ok {
 | 
			
		||||
					return nil
 | 
			
		||||
				}
 | 
			
		||||
				urnParts, err := extractURNParts(missingURN, serviceURNPrefix)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				dcp.ServiceTypes[missingURN] = urnParts
 | 
			
		||||
				return nil
 | 
			
		||||
			}, totalBytesHack,
 | 
			
		||||
		Src: upnpdotorg{
 | 
			
		||||
			DocURL:     "http://upnp.org/specs/gw/UPnP-gw-InternetGatewayDevice-v2-Device.pdf",
 | 
			
		||||
			XMLSpecURL: "http://upnp.org/specs/gw/UPnP-gw-IGD-Testfiles-20110224.zip",
 | 
			
		||||
			Hacks: []DCPHackFn{
 | 
			
		||||
				fixMissingURN("urn:schemas-upnp-org:service:WANIPv6FirewallControl:1"),
 | 
			
		||||
				fixTotalBytes("urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1"),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:         "av1",
 | 
			
		||||
		OfficialName: "MediaServer v1 and MediaRenderer v1",
 | 
			
		||||
		DocURL:       "http://upnp.org/specs/av/av1/",
 | 
			
		||||
		XMLSpecURL:   "http://upnp.org/specs/av/UPnP-av-TestFiles-20070927.zip",
 | 
			
		||||
		Src: upnpdotorg{
 | 
			
		||||
			DocURL:     "http://upnp.org/specs/av/av1/",
 | 
			
		||||
			XMLSpecURL: "http://upnp.org/specs/av/UPnP-av-TestFiles-20070927.zip",
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:         "ocf/internetgateway1",
 | 
			
		||||
		OfficialName: "Internet Gateway Device v1 - Open Connectivity Foundation",
 | 
			
		||||
		Src: openconnectivitydotorg{
 | 
			
		||||
			SpecsURL:       ocfSpecsURL,
 | 
			
		||||
			DocPath:        "*/DeviceProtection_1/UPnP-gw-*v1*.pdf",
 | 
			
		||||
			XMLSpecZipPath: "*/DeviceProtection_1/UPnP-gw-IGD-TestFiles-*.zip",
 | 
			
		||||
			XMLServicePath: []string{"*/service/*1.xml"},
 | 
			
		||||
			XMLDevicePath:  []string{"*/device/*1.xml"},
 | 
			
		||||
			Hacks: []DCPHackFn{
 | 
			
		||||
				fixMissingURN("urn:schemas-upnp-org:service:DeviceProtection:1"),
 | 
			
		||||
				fixMissingURN("urn:schemas-upnp-org:service:WANIPv6FirewallControl:1"),
 | 
			
		||||
				fixTotalBytes(),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:         "ocf/internetgateway2",
 | 
			
		||||
		OfficialName: "Internet Gateway Device v2 - Open Connectivity Foundation",
 | 
			
		||||
		Src: openconnectivitydotorg{
 | 
			
		||||
			SpecsURL:       ocfSpecsURL,
 | 
			
		||||
			DocPath:        "*/Internet Gateway_2/UPnP-gw-*.pdf",
 | 
			
		||||
			XMLSpecZipPath: "*/Internet Gateway_2/UPnP-gw-IGD-TestFiles-*.zip",
 | 
			
		||||
			XMLServicePath: []string{"*/service/*1.xml", "*/service/*2.xml"},
 | 
			
		||||
			XMLDevicePath:  []string{"*/device/*1.xml", "*/device/*2.xml"},
 | 
			
		||||
			Hacks: []DCPHackFn{
 | 
			
		||||
				fixMissingURN("urn:schemas-upnp-org:service:DeviceProtection:1"),
 | 
			
		||||
				fixTotalBytes(),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func totalBytesHack(dcp *DCP) error {
 | 
			
		||||
	for _, service := range dcp.Services {
 | 
			
		||||
		if service.URN == "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" {
 | 
			
		||||
			variables := service.SCPD.StateVariables
 | 
			
		||||
			for key, variable := range variables {
 | 
			
		||||
				varName := variable.Name
 | 
			
		||||
				if varName == "TotalBytesSent" || varName == "TotalBytesReceived" {
 | 
			
		||||
					// Fix size of total bytes which is by default ui4 or maximum 4 GiB.
 | 
			
		||||
					variable.DataType.Name = "ui8"
 | 
			
		||||
					variables[key] = variable
 | 
			
		||||
func fixTotalBytes(malformedURNs ...string) func(dcp *DCP) error {
 | 
			
		||||
	malformedVariables := []string{
 | 
			
		||||
		"TotalBytesSent",
 | 
			
		||||
		"TotalBytesReceived",
 | 
			
		||||
	}
 | 
			
		||||
	return func(dcp *DCP) error {
 | 
			
		||||
		for _, service := range dcp.Services {
 | 
			
		||||
			var process bool
 | 
			
		||||
			for _, malformedURN := range malformedURNs {
 | 
			
		||||
				if service.URN == malformedURN {
 | 
			
		||||
					process = true
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if process || len(malformedURNs) < 1 {
 | 
			
		||||
				variables := service.SCPD.StateVariables
 | 
			
		||||
				for key, variable := range variables {
 | 
			
		||||
					varName := variable.Name
 | 
			
		||||
					for _, malformedVariable := range malformedVariables {
 | 
			
		||||
						if strings.HasSuffix(varName, malformedVariable) {
 | 
			
		||||
							// Fix size of total bytes which is by default ui4 or maximum 4 GiB.
 | 
			
		||||
							variable.DataType.Name = "ui8"
 | 
			
		||||
							variables[key] = variable
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
func fixMissingURN(missingURNs ...string) func(dcp *DCP) error {
 | 
			
		||||
	return func(dcp *DCP) error {
 | 
			
		||||
		for _, missingURN := range missingURNs {
 | 
			
		||||
			if _, ok := dcp.ServiceTypes[missingURN]; ok {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			urnParts, err := extractURNParts(missingURN, serviceURNPrefix)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			dcp.ServiceTypes[missingURN] = urnParts
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type DCPHackFn func(*DCP) error
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										101
									
								
								cmd/goupnpdcpgen/provider.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								cmd/goupnpdcpgen/provider.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,101 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"archive/zip"
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type dcpProvider interface {
 | 
			
		||||
	process(tmpdir, name string, dcp *DCP) error
 | 
			
		||||
}
 | 
			
		||||
type upnpdotorg struct {
 | 
			
		||||
	DocURL     string // Optional - URL for further documentation about the DCP.
 | 
			
		||||
	XMLSpecURL string // Where to download the XML spec from.
 | 
			
		||||
	// Any special-case functions to run against the DCP before writing it out.
 | 
			
		||||
	Hacks []DCPHackFn
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (u upnpdotorg) process(tmpdir, name string, dcp *DCP) error {
 | 
			
		||||
	dcp.DocURLs = append(dcp.DocURLs, u.DocURL)
 | 
			
		||||
	specFilename := filepath.Join(tmpdir, name+".zip")
 | 
			
		||||
	err := acquireFile(specFilename, u.XMLSpecURL)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("could not acquire spec for %s: %v", name, err)
 | 
			
		||||
	}
 | 
			
		||||
	archive, err := zip.OpenReader(specFilename)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("error reading zip file %q: %v", specFilename, err)
 | 
			
		||||
	}
 | 
			
		||||
	defer archive.Close()
 | 
			
		||||
	if err := dcp.processZipFile(archive.File, []string{"*/device/*.xml"}, []string{"*/service/*.xml"}); err != nil {
 | 
			
		||||
		return fmt.Errorf("error processing spec file %q: %v", specFilename, err)
 | 
			
		||||
	}
 | 
			
		||||
	for i, hack := range u.Hacks {
 | 
			
		||||
		if err := hack(dcp); err != nil {
 | 
			
		||||
			return fmt.Errorf("error with Hack[%d] for %s: %v", i, name, err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const ocfSpecsURL = "https://openconnectivity.org/upnp-specs/upnpresources.zip"
 | 
			
		||||
 | 
			
		||||
type openconnectivitydotorg struct {
 | 
			
		||||
	DocPath        string // Optional - Glob to the related documentation about the DCP.
 | 
			
		||||
	SpecsURL       string // The HTTP location of the zip archive containing all XML spec.
 | 
			
		||||
	XMLSpecZipPath string // Glob to the zip XML spec file within upnpresources.zip.
 | 
			
		||||
	// Glob to the services XML files within the ZIP matching XMLSpecZipPath.
 | 
			
		||||
	XMLServicePath []string
 | 
			
		||||
	// Glob to the devices XML files within the ZIP matching XMLSpecZipPath.
 | 
			
		||||
	XMLDevicePath []string
 | 
			
		||||
	// Any special-case functions to run against the DCP before writing it out.
 | 
			
		||||
	Hacks []DCPHackFn
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o openconnectivitydotorg) process(tmpdir, name string, dcp *DCP) error {
 | 
			
		||||
	fname := filepath.Base(name)
 | 
			
		||||
	allSpecsFilename := filepath.Join(tmpdir, "openconnectivitydotorg_"+fname+".zip")
 | 
			
		||||
	err := acquireFile(allSpecsFilename, o.SpecsURL)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("could not acquire specs %s: %v", name, err)
 | 
			
		||||
	}
 | 
			
		||||
	allSpecsArchive, err := zip.OpenReader(allSpecsFilename)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("error reading zip file %q: %v", allSpecsFilename, err)
 | 
			
		||||
	}
 | 
			
		||||
	specsArchives := globFiles(o.XMLSpecZipPath, allSpecsArchive.File)
 | 
			
		||||
	if len(specsArchives) < 1 {
 | 
			
		||||
		return fmt.Errorf("zip archive %q does not contain specifications at %q", allSpecsFilename, o.XMLSpecZipPath)
 | 
			
		||||
	}
 | 
			
		||||
	for _, specArchive := range specsArchives {
 | 
			
		||||
		f, err := specArchive.Open()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fmt.Errorf("error reading zip file %q: %v", specArchive.Name, err)
 | 
			
		||||
		}
 | 
			
		||||
		defer f.Close()
 | 
			
		||||
		b, err := ioutil.ReadAll(f)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		archive, err := zip.NewReader(bytes.NewReader(b), specArchive.FileInfo().Size())
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fmt.Errorf("error reading zip file %q: %v", specArchive.Name, err)
 | 
			
		||||
		}
 | 
			
		||||
		if err := dcp.processZipFile(archive.File, o.XMLDevicePath, o.XMLServicePath); err != nil {
 | 
			
		||||
			return fmt.Errorf("error processing spec file %q: %v", specArchive.Name, err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for i, hack := range o.Hacks {
 | 
			
		||||
		if err := hack(dcp); err != nil {
 | 
			
		||||
			return fmt.Errorf("error with Hack[%d] for %s: %v", i, name, err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, d := range globFiles(o.DocPath, allSpecsArchive.File) {
 | 
			
		||||
		dcp.DocURLs = append(dcp.DocURLs, d.Name)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user