mirror of
https://github.com/blacktop/ipsw.git
synced 2026-06-07 12:27:36 +00:00
110 lines
2.3 KiB
Go
110 lines
2.3 KiB
Go
package dyld
|
|
|
|
import (
|
|
"io"
|
|
|
|
"github.com/blacktop/go-macho/types"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// Seek whence values.
|
|
const (
|
|
SeekStart = 0 // seek relative to the origin of the file
|
|
SeekCurrent = 1 // seek relative to the current offset
|
|
SeekEnd = 2 // seek relative to the end
|
|
)
|
|
|
|
var EOF = errors.New("EOF")
|
|
|
|
type DyldSharedCacheReader struct {
|
|
base int64
|
|
off int64
|
|
limit int64
|
|
|
|
cache *File
|
|
ruuid types.UUID
|
|
}
|
|
|
|
// TODO: 🚧 finish this and replace all the other readers with it
|
|
func NewDyldSharedCacheReader(f *File, off int64) *DyldSharedCacheReader {
|
|
return &DyldSharedCacheReader{
|
|
base: off,
|
|
off: off,
|
|
limit: f.size,
|
|
cache: f,
|
|
}
|
|
}
|
|
|
|
func (cr *DyldSharedCacheReader) Seek(offset int64, whence int) (n int64, err error) {
|
|
switch whence {
|
|
default:
|
|
return 0, errors.New("Seek: invalid whence")
|
|
case SeekStart:
|
|
offset += cr.base
|
|
case SeekCurrent:
|
|
offset += cr.off
|
|
case SeekEnd:
|
|
offset += cr.limit
|
|
}
|
|
if offset < cr.base {
|
|
return 0, errors.New("Seek: invalid offset")
|
|
}
|
|
cr.off = offset
|
|
cr.ruuid, _, err = cr.cache.GetCacheVMAddress(uint64(offset))
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return offset - cr.base, nil
|
|
}
|
|
|
|
func (cr *DyldSharedCacheReader) SeekToAddr(addr uint64) error {
|
|
uuid, offset, err := cr.cache.GetOffset(addr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
cr.ruuid = uuid
|
|
_, err = cr.Seek(int64(offset), io.SeekStart)
|
|
return err
|
|
}
|
|
|
|
func (cr *DyldSharedCacheReader) Read(p []byte) (n int, err error) {
|
|
if cr.off >= cr.limit {
|
|
return 0, EOF
|
|
}
|
|
if max := cr.limit - cr.off; int64(len(p)) > max {
|
|
p = p[0:max]
|
|
}
|
|
n, err = cr.ReadAt(p, cr.off)
|
|
cr.off += int64(n)
|
|
return
|
|
}
|
|
|
|
func (cr *DyldSharedCacheReader) ReadAt(p []byte, off int64) (n int, err error) {
|
|
if off < 0 || off >= cr.limit-cr.base {
|
|
return 0, EOF
|
|
}
|
|
off += cr.base
|
|
if max := cr.limit - off; int64(len(p)) > max {
|
|
p = p[0:max]
|
|
n, err = cr.ReadAt(p, off)
|
|
if err == nil {
|
|
err = EOF
|
|
}
|
|
return n, err
|
|
}
|
|
return cr.cache.r[cr.ruuid].ReadAt(p, off)
|
|
}
|
|
|
|
// ReadAtAddr reads data at a given virtual address
|
|
func (cr *DyldSharedCacheReader) ReadAtAddr(buf []byte, addr uint64) (int, error) {
|
|
uuid, off, err := cr.cache.GetOffset(addr)
|
|
if err != nil {
|
|
return -1, err
|
|
}
|
|
cr.ruuid = uuid
|
|
return cr.cache.r[cr.ruuid].ReadAt(buf, int64(off))
|
|
}
|
|
|
|
// Size returns the size of the section in bytes.
|
|
func (cr *DyldSharedCacheReader) Size() int64 { return cr.limit - cr.base }
|