Example #1
0
func (dec decoder) Decode(x interface{}) error {
	err := dec.dec.Decode(x)
	if err != nil {
		return err
	}
	var names []string
	err = dec.dec.Decode(&names)
	if err != nil {
		return err
	}
	files := make(map[string][]*File)
	typeapply.Do(func(f *File) {
		if f != nil && f.Name != "" {
			files[f.Name] = append(files[f.Name], f)
		}
	},
		x)
	for _, name := range names {
		var out io.WriteSeeker
		if files[name] == nil {
			out = nullWriter{}
		} else {
			samefiles := files[name]
			f := samefiles[0]
			if f == nil {
				return errors.New("file not found in manifest")
			}
			f.file, err = ioutil.TempFile("", "filemarshal")
			if err != nil {
				return err
			}
			f.Name = f.file.Name()
			for _, g := range samefiles[1:] {
				*g = *f
			}
			out = f.file
		}
		for {
			buf := []byte(nil)
			err = dec.dec.Decode(&buf)
			if err != nil {
				return err
			}
			if len(buf) == 0 {
				break
			}
			_, err = out.Write(buf)
			if err != nil {
				return err
			}
		}
		out.Seek(0, 0)
	}
	return nil
}
Example #2
0
//  Encode writes a representation of x to the encoder.  We have to be
//  careful about how we do this, because the data type that we decode
//  into does not necessarily match the encoded data type.  Fields may
//  occur in a different order, and some fields may not occur in the
//  final type.  To cope with this, we assume that each Name in an
//  os.File is unique.  We first encode x itself, followed by a list of
//  the file names within it, followed by the data from all those files,
//  in list order, as a sequence of byte slices, terminated with a
//  zero-length slice.
//
//  When the decoder decodes the value, it can then associate the correct
//  item in the data structure with the correct file stream.
func (enc encoder) Encode(x interface{}) error {
	// TODO some kind of signature so that we can be more
	// robust if we try to Decode a stream that has not
	// been encoded with filemarshal?

	err := enc.enc.Encode(x)
	if err != nil {
		return err
	}
	files := make(map[string]*File)
	var names []string
	typeapply.Do(func(f *File) {
		if f.Name != "" && files[f.Name] == nil {
			names = append(names, f.Name)
			files[f.Name] = f
		}
	},
		x)
	err = enc.enc.Encode(names)
	if err != nil {
		return err
	}
	buf := make([]byte, 8192)
	for _, name := range names {
		off := int64(0)
		f := files[name]
		for {
			n, err := f.file.ReadAt(buf, off)
			if n > 0 {
				err = enc.enc.Encode(buf[0:n])
				if err != nil {
					return err
				}
			}
			if err != nil {
				break
			}
			off += int64(n)
		}
		err = enc.enc.Encode([]byte{})
		if err != nil {
			return err
		}
	}
	return nil
}