Imported Upstream version 4.8.1
[platform/upstream/gcc48.git] / libgo / go / go / types / exportdata.go
1 // Copyright 2011 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 // This file implements FindGcExportData.
6
7 package types
8
9 import (
10         "bufio"
11         "errors"
12         "fmt"
13         "io"
14         "strconv"
15         "strings"
16 )
17
18 func readGopackHeader(r *bufio.Reader) (name string, size int, err error) {
19         // See $GOROOT/include/ar.h.
20         hdr := make([]byte, 16+12+6+6+8+10+2)
21         _, err = io.ReadFull(r, hdr)
22         if err != nil {
23                 return
24         }
25         // leave for debugging
26         if false {
27                 fmt.Printf("header: %s", hdr)
28         }
29         s := strings.TrimSpace(string(hdr[16+12+6+6+8:][:10]))
30         size, err = strconv.Atoi(s)
31         if err != nil || hdr[len(hdr)-2] != '`' || hdr[len(hdr)-1] != '\n' {
32                 err = errors.New("invalid archive header")
33                 return
34         }
35         name = strings.TrimSpace(string(hdr[:16]))
36         return
37 }
38
39 // FindGcExportData positions the reader r at the beginning of the
40 // export data section of an underlying GC-created object/archive
41 // file by reading from it. The reader must be positioned at the
42 // start of the file before calling this function.
43 //
44 func FindGcExportData(r *bufio.Reader) (err error) {
45         // Read first line to make sure this is an object file.
46         line, err := r.ReadSlice('\n')
47         if err != nil {
48                 return
49         }
50         if string(line) == "!<arch>\n" {
51                 // Archive file.  Scan to __.PKGDEF, which should
52                 // be second archive entry.
53                 var name string
54                 var size int
55
56                 // First entry should be __.GOSYMDEF.
57                 // Older archives used __.SYMDEF, so allow that too.
58                 // Read and discard.
59                 if name, size, err = readGopackHeader(r); err != nil {
60                         return
61                 }
62                 if name != "__.SYMDEF" && name != "__.GOSYMDEF" {
63                         err = errors.New("go archive does not begin with __.SYMDEF or __.GOSYMDEF")
64                         return
65                 }
66                 const block = 4096
67                 tmp := make([]byte, block)
68                 for size > 0 {
69                         n := size
70                         if n > block {
71                                 n = block
72                         }
73                         if _, err = io.ReadFull(r, tmp[:n]); err != nil {
74                                 return
75                         }
76                         size -= n
77                 }
78
79                 // Second entry should be __.PKGDEF.
80                 if name, size, err = readGopackHeader(r); err != nil {
81                         return
82                 }
83                 if name != "__.PKGDEF" {
84                         err = errors.New("go archive is missing __.PKGDEF")
85                         return
86                 }
87
88                 // Read first line of __.PKGDEF data, so that line
89                 // is once again the first line of the input.
90                 if line, err = r.ReadSlice('\n'); err != nil {
91                         return
92                 }
93         }
94
95         // Now at __.PKGDEF in archive or still at beginning of file.
96         // Either way, line should begin with "go object ".
97         if !strings.HasPrefix(string(line), "go object ") {
98                 err = errors.New("not a go object file")
99                 return
100         }
101
102         // Skip over object header to export data.
103         // Begins after first line with $$.
104         for line[0] != '$' {
105                 if line, err = r.ReadSlice('\n'); err != nil {
106                         return
107                 }
108         }
109
110         return
111 }