mirror of
				https://github.com/beego/bee.git
				synced 2025-10-30 21:03:22 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			147 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			147 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2014 The Go Authors.  All rights reserved.
 | |
| // Use of this source code is governed by a BSD-style
 | |
| // license that can be found in the LICENSE file.
 | |
| 
 | |
| package macho
 | |
| 
 | |
| import (
 | |
| 	"encoding/binary"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"os"
 | |
| )
 | |
| 
 | |
| // A FatFile is a Mach-O universal binary that contains at least one architecture.
 | |
| type FatFile struct {
 | |
| 	Magic  uint32
 | |
| 	Arches []FatArch
 | |
| 	closer io.Closer
 | |
| }
 | |
| 
 | |
| // A FatArchHeader represents a fat header for a specific image architecture.
 | |
| type FatArchHeader struct {
 | |
| 	Cpu    Cpu
 | |
| 	SubCpu uint32
 | |
| 	Offset uint32
 | |
| 	Size   uint32
 | |
| 	Align  uint32
 | |
| }
 | |
| 
 | |
| const fatArchHeaderSize = 5 * 4
 | |
| 
 | |
| // A FatArch is a Mach-O File inside a FatFile.
 | |
| type FatArch struct {
 | |
| 	FatArchHeader
 | |
| 	*File
 | |
| }
 | |
| 
 | |
| // ErrNotFat is returned from NewFatFile or OpenFat when the file is not a
 | |
| // universal binary but may be a thin binary, based on its magic number.
 | |
| var ErrNotFat = &FormatError{0, "not a fat Mach-O file", nil}
 | |
| 
 | |
| // NewFatFile creates a new FatFile for accessing all the Mach-O images in a
 | |
| // universal binary. The Mach-O binary is expected to start at position 0 in
 | |
| // the ReaderAt.
 | |
| func NewFatFile(r io.ReaderAt) (*FatFile, error) {
 | |
| 	var ff FatFile
 | |
| 	sr := io.NewSectionReader(r, 0, 1<<63-1)
 | |
| 
 | |
| 	// Read the fat_header struct, which is always in big endian.
 | |
| 	// Start with the magic number.
 | |
| 	err := binary.Read(sr, binary.BigEndian, &ff.Magic)
 | |
| 	if err != nil {
 | |
| 		return nil, &FormatError{0, "error reading magic number", nil}
 | |
| 	} else if ff.Magic != MagicFat {
 | |
| 		// See if this is a Mach-O file via its magic number. The magic
 | |
| 		// must be converted to little endian first though.
 | |
| 		var buf [4]byte
 | |
| 		binary.BigEndian.PutUint32(buf[:], ff.Magic)
 | |
| 		leMagic := binary.LittleEndian.Uint32(buf[:])
 | |
| 		if leMagic == Magic32 || leMagic == Magic64 {
 | |
| 			return nil, ErrNotFat
 | |
| 		} else {
 | |
| 			return nil, &FormatError{0, "invalid magic number", nil}
 | |
| 		}
 | |
| 	}
 | |
| 	offset := int64(4)
 | |
| 
 | |
| 	// Read the number of FatArchHeaders that come after the fat_header.
 | |
| 	var narch uint32
 | |
| 	err = binary.Read(sr, binary.BigEndian, &narch)
 | |
| 	if err != nil {
 | |
| 		return nil, &FormatError{offset, "invalid fat_header", nil}
 | |
| 	}
 | |
| 	offset += 4
 | |
| 
 | |
| 	if narch < 1 {
 | |
| 		return nil, &FormatError{offset, "file contains no images", nil}
 | |
| 	}
 | |
| 
 | |
| 	// Combine the Cpu and SubCpu (both uint32) into a uint64 to make sure
 | |
| 	// there are not duplicate architectures.
 | |
| 	seenArches := make(map[uint64]bool, narch)
 | |
| 	// Make sure that all images are for the same MH_ type.
 | |
| 	var machoType Type
 | |
| 
 | |
| 	// Following the fat_header comes narch fat_arch structs that index
 | |
| 	// Mach-O images further in the file.
 | |
| 	ff.Arches = make([]FatArch, narch)
 | |
| 	for i := uint32(0); i < narch; i++ {
 | |
| 		fa := &ff.Arches[i]
 | |
| 		err = binary.Read(sr, binary.BigEndian, &fa.FatArchHeader)
 | |
| 		if err != nil {
 | |
| 			return nil, &FormatError{offset, "invalid fat_arch header", nil}
 | |
| 		}
 | |
| 		offset += fatArchHeaderSize
 | |
| 
 | |
| 		fr := io.NewSectionReader(r, int64(fa.Offset), int64(fa.Size))
 | |
| 		fa.File, err = NewFile(fr)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 
 | |
| 		// Make sure the architecture for this image is not duplicate.
 | |
| 		seenArch := (uint64(fa.Cpu) << 32) | uint64(fa.SubCpu)
 | |
| 		if o, k := seenArches[seenArch]; o || k {
 | |
| 			return nil, &FormatError{offset, fmt.Sprintf("duplicate architecture cpu=%v, subcpu=%#x", fa.Cpu, fa.SubCpu), nil}
 | |
| 		}
 | |
| 		seenArches[seenArch] = true
 | |
| 
 | |
| 		// Make sure the Mach-O type matches that of the first image.
 | |
| 		if i == 0 {
 | |
| 			machoType = fa.Type
 | |
| 		} else {
 | |
| 			if fa.Type != machoType {
 | |
| 				return nil, &FormatError{offset, fmt.Sprintf("Mach-O type for architecture #%d (type=%#x) does not match first (type=%#x)", i, fa.Type, machoType), nil}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return &ff, nil
 | |
| }
 | |
| 
 | |
| // OpenFat opens the named file using os.Open and prepares it for use as a Mach-O
 | |
| // universal binary.
 | |
| func OpenFat(name string) (ff *FatFile, err error) {
 | |
| 	f, err := os.Open(name)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	ff, err = NewFatFile(f)
 | |
| 	if err != nil {
 | |
| 		f.Close()
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	ff.closer = f
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (ff *FatFile) Close() error {
 | |
| 	var err error
 | |
| 	if ff.closer != nil {
 | |
| 		err = ff.closer.Close()
 | |
| 		ff.closer = nil
 | |
| 	}
 | |
| 	return err
 | |
| }
 | 
