github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/mobile/gl/dll_windows.go (about)

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package gl
     6  
     7  import (
     8  	"archive/tar"
     9  	"compress/gzip"
    10  	"fmt"
    11  	"io"
    12  	"io/ioutil"
    13  	"log"
    14  	"net/http"
    15  	"os"
    16  	"path/filepath"
    17  	"runtime"
    18  )
    19  
    20  var debug = log.New(ioutil.Discard, "gl: ", log.LstdFlags)
    21  
    22  func downloadDLLs() (path string, err error) {
    23  	url := "https://dl.google.com/go/mobile/angle-dd5c5b-" + runtime.GOARCH + ".tgz"
    24  	debug.Printf("downloading %s", url)
    25  	resp, err := http.Get(url)
    26  	if err != nil {
    27  		return "", fmt.Errorf("gl: %v", err)
    28  	}
    29  	defer func() {
    30  		err2 := resp.Body.Close()
    31  		if err == nil && err2 != nil {
    32  			err = fmt.Errorf("gl: error reading body from %v: %v", url, err2)
    33  		}
    34  	}()
    35  	if resp.StatusCode != http.StatusOK {
    36  		err := fmt.Errorf("gl: error fetching %v, status: %v", url, resp.Status)
    37  		return "", err
    38  	}
    39  
    40  	r, err := gzip.NewReader(resp.Body)
    41  	if err != nil {
    42  		return "", fmt.Errorf("gl: error reading gzip from %v: %v", url, err)
    43  	}
    44  	tr := tar.NewReader(r)
    45  	var bytesGLESv2, bytesEGL []byte
    46  	for {
    47  		header, err := tr.Next()
    48  		if err == io.EOF {
    49  			break
    50  		}
    51  		if err != nil {
    52  			return "", fmt.Errorf("gl: error reading tar from %v: %v", url, err)
    53  		}
    54  		switch header.Name {
    55  		case "angle-" + runtime.GOARCH + "/libglesv2.dll":
    56  			bytesGLESv2, err = ioutil.ReadAll(tr)
    57  		case "angle-" + runtime.GOARCH + "/libegl.dll":
    58  			bytesEGL, err = ioutil.ReadAll(tr)
    59  		default: // skip
    60  		}
    61  		if err != nil {
    62  			return "", fmt.Errorf("gl: error reading %v from %v: %v", header.Name, url, err)
    63  		}
    64  	}
    65  	if len(bytesGLESv2) == 0 || len(bytesEGL) == 0 {
    66  		return "", fmt.Errorf("gl: did not find both DLLs in %v", url)
    67  	}
    68  
    69  	writeDLLs := func(path string) error {
    70  		if err := ioutil.WriteFile(filepath.Join(path, "libglesv2.dll"), bytesGLESv2, 0755); err != nil {
    71  			return fmt.Errorf("gl: cannot install ANGLE: %v", err)
    72  		}
    73  		if err := ioutil.WriteFile(filepath.Join(path, "libegl.dll"), bytesEGL, 0755); err != nil {
    74  			return fmt.Errorf("gl: cannot install ANGLE: %v", err)
    75  		}
    76  		return nil
    77  	}
    78  
    79  	// First, we attempt to install these DLLs in LOCALAPPDATA/Shiny.
    80  	//
    81  	// Traditionally we would use the system32 directory, but it is
    82  	// no longer writable by normal programs.
    83  	os.MkdirAll(appdataPath(), 0775)
    84  	if err := writeDLLs(appdataPath()); err == nil {
    85  		return appdataPath(), nil
    86  	}
    87  	debug.Printf("DLLs could not be written to %s", appdataPath())
    88  
    89  	// Second, install in GOPATH/pkg if it exists.
    90  	gopath := os.Getenv("GOPATH")
    91  	gopathpkg := filepath.Join(gopath, "pkg")
    92  	if _, err := os.Stat(gopathpkg); err == nil && gopath != "" {
    93  		if err := writeDLLs(gopathpkg); err == nil {
    94  			return gopathpkg, nil
    95  		}
    96  	}
    97  	debug.Printf("DLLs could not be written to GOPATH")
    98  
    99  	// Third, pick a temporary directory.
   100  	tmp := os.TempDir()
   101  	if err := writeDLLs(tmp); err != nil {
   102  		return "", fmt.Errorf("gl: unable to install ANGLE DLLs: %v", err)
   103  	}
   104  	return tmp, nil
   105  }
   106  
   107  func appdataPath() string {
   108  	return filepath.Join(os.Getenv("LOCALAPPDATA"), "GoGL", runtime.GOARCH)
   109  }
   110  
   111  func findDLLs() (err error) {
   112  	load := func(path string) (bool, error) {
   113  		if path != "" {
   114  			LibGLESv2.Name = filepath.Join(path, filepath.Base(LibGLESv2.Name))
   115  			LibEGL.Name = filepath.Join(path, filepath.Base(LibEGL.Name))
   116  		}
   117  		if err := LibGLESv2.Load(); err == nil {
   118  			if err := LibEGL.Load(); err != nil {
   119  				return false, fmt.Errorf("gl: loaded libglesv2 but not libegl: %v", err)
   120  			}
   121  			if path == "" {
   122  				debug.Printf("DLLs found")
   123  			} else {
   124  				debug.Printf("DLLs found in: %q", path)
   125  			}
   126  			return true, nil
   127  		}
   128  		return false, nil
   129  	}
   130  
   131  	// Look in the system directory.
   132  	if ok, err := load(""); ok || err != nil {
   133  		return err
   134  	}
   135  
   136  	// Look in the AppData directory.
   137  	if ok, err := load(appdataPath()); ok || err != nil {
   138  		return err
   139  	}
   140  
   141  	// TODO: Look for a Chrome installation.
   142  
   143  	// Look in GOPATH/pkg.
   144  	if ok, err := load(filepath.Join(os.Getenv("GOPATH"), "pkg")); ok || err != nil {
   145  		return err
   146  	}
   147  
   148  	// Look in temporary directory.
   149  	if ok, err := load(os.TempDir()); ok || err != nil {
   150  		return err
   151  	}
   152  
   153  	// Download the DLL binary.
   154  	path, err := downloadDLLs()
   155  	if err != nil {
   156  		return err
   157  	}
   158  	debug.Printf("DLLs written to %s", path)
   159  	if ok, err := load(path); !ok || err != nil {
   160  		return fmt.Errorf("gl: unable to load ANGLE after installation: %v", err)
   161  	}
   162  	return nil
   163  }