format.go 2.78 KB
Newer Older
1 2 3 4 5 6 7
// Package format implements a data format for files in the ipfs filesystem
// It is not the only format in ipfs, but it is the one that the filesystem assumes
package unixfs

import (
	"errors"

8 9
	proto "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto"
	pb "github.com/jbenet/go-ipfs/unixfs/pb"
10 11 12 13 14 15
)

var ErrMalformedFileFormat = errors.New("malformed data in file format")
var ErrInvalidDirLocation = errors.New("found directory node in unexpected place")
var ErrUnrecognizedType = errors.New("unrecognized node type")

16 17
func FromBytes(data []byte) (*pb.Data, error) {
	pbdata := new(pb.Data)
18 19 20 21 22 23 24 25
	err := proto.Unmarshal(data, pbdata)
	if err != nil {
		return nil, err
	}
	return pbdata, nil
}

func FilePBData(data []byte, totalsize uint64) []byte {
26 27
	pbfile := new(pb.Data)
	typ := pb.Data_File
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
	pbfile.Type = &typ
	pbfile.Data = data
	pbfile.Filesize = proto.Uint64(totalsize)

	data, err := proto.Marshal(pbfile)
	if err != nil {
		// This really shouldnt happen, i promise
		// The only failure case for marshal is if required fields
		// are not filled out, and they all are. If the proto object
		// gets changed and nobody updates this function, the code
		// should panic due to programmer error
		panic(err)
	}
	return data
}

// Returns Bytes that represent a Directory
func FolderPBData() []byte {
46 47
	pbfile := new(pb.Data)
	typ := pb.Data_Directory
48 49 50 51 52 53 54 55 56 57 58
	pbfile.Type = &typ

	data, err := proto.Marshal(pbfile)
	if err != nil {
		//this really shouldnt happen, i promise
		panic(err)
	}
	return data
}

func WrapData(b []byte) []byte {
59 60
	pbdata := new(pb.Data)
	typ := pb.Data_Raw
61 62 63 64 65 66 67 68 69 70 71 72 73
	pbdata.Data = b
	pbdata.Type = &typ

	out, err := proto.Marshal(pbdata)
	if err != nil {
		// This shouldnt happen. seriously.
		panic(err)
	}

	return out
}

func UnwrapData(data []byte) ([]byte, error) {
74
	pbdata := new(pb.Data)
75 76 77 78 79 80 81 82
	err := proto.Unmarshal(data, pbdata)
	if err != nil {
		return nil, err
	}
	return pbdata.GetData(), nil
}

func DataSize(data []byte) (uint64, error) {
83
	pbdata := new(pb.Data)
84 85 86 87 88 89
	err := proto.Unmarshal(data, pbdata)
	if err != nil {
		return 0, err
	}

	switch pbdata.GetType() {
90
	case pb.Data_Directory:
91
		return 0, errors.New("Cant get data size of directory!")
92
	case pb.Data_File:
93
		return pbdata.GetFilesize(), nil
94
	case pb.Data_Raw:
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
		return uint64(len(pbdata.GetData())), nil
	default:
		return 0, errors.New("Unrecognized node data type!")
	}
}

type MultiBlock struct {
	Data       []byte
	blocksizes []uint64
	subtotal   uint64
}

func (mb *MultiBlock) AddBlockSize(s uint64) {
	mb.subtotal += s
	mb.blocksizes = append(mb.blocksizes, s)
}

func (mb *MultiBlock) GetBytes() ([]byte, error) {
113 114
	pbn := new(pb.Data)
	t := pb.Data_File
115 116 117 118 119 120
	pbn.Type = &t
	pbn.Filesize = proto.Uint64(uint64(len(mb.Data)) + mb.subtotal)
	pbn.Blocksizes = mb.blocksizes
	pbn.Data = mb.Data
	return proto.Marshal(pbn)
}