func (d *deltaeval) Copy(repo *libgit.Repository, src ObjectReference, offset, length uint64) { id, _ := libgit.NewId(src) _, _, r, err := repo.GetRawObject(id, false) if err != nil { panic(err) } defer r.Close() if offset > 0 { tmp := make([]byte, offset) n, err := io.ReadFull(r, tmp) if err != nil { panic(err) } if n == 0 || uint64(n) != offset { panic("Couldn't correctly read offset.") } } reading := make([]byte, length) n, err := io.ReadFull(r, reading) if uint64(n) != length || err != nil { panic("Error copying data") } d.value = append(d.value, reading...) }
// Calculate the final reslt of a REF_DELTA. This is largely // based on the delta algorithm as described at: // http://stefan.saasen.me/articles/git-clone-in-haskell-from-the-bottom-up/#pack_file_format func calculateDelta(repo *libgit.Repository, reference ObjectReference, delta []byte) (PackEntryType, []byte) { deltaStream := bytes.NewBuffer(delta) // Read 2 variable length strings for the source and target buffer // length // read the source length, but we don't care. We just want to advance // the deltaStream pointer the proper amount. ReadVariable(deltaStream) // Read the target length so we know when we've finished processing // the delta stream. targetLength := ReadVariable(deltaStream) d := deltaeval{} for { d.DoInstruction(repo, deltaStream, reference, targetLength) if targetLength == uint64(len(d.value)) { break } if len(d.value) > int(targetLength) { panic("Read too much data from delta stream") } } // GetRawObject to find the underlying type of the original // reference id, err := libgit.NewId(reference) if err != nil { panic(err) } objt, _, _, err := repo.GetRawObject(id, true) if err != nil { panic(err) } switch objt { case libgit.ObjectCommit: return OBJ_COMMIT, d.value case libgit.ObjectTree: return OBJ_TREE, d.value case libgit.ObjectBlob: return OBJ_BLOB, d.value case libgit.ObjectTag: return OBJ_TAG, d.value } panic("Unhandle object type while calculating delta.") return 0, nil }