Skip to content

Commit b101b0d

Browse files
committed
Add binary patch types and binary marker parsing
The binary marker is the text that appears where a text fragment normally would and indicates that the file is binary. It's not quite a header, because content is optional in a binary patch. If the patch does include binary fragments, they have their own format, with a header.
1 parent a0b33e3 commit b101b0d

File tree

2 files changed

+53
-3
lines changed

2 files changed

+53
-3
lines changed

gitdiff/gitdiff.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ type File struct {
2626
// TextFragments contains the fragments describing changes to a text file. It
2727
// may be empty if the file is empty or if only the mode changes.
2828
TextFragments []*TextFragment
29+
30+
// IsBinary is true if the file is a binary file. If the patch includes
31+
// binary data, BinaryFragment will be non-nil and describe the changes to
32+
// the data. If the patch is reversible, ReverseBinaryFragment will also be
33+
// non-nil and describe the changes needed to restore the original file
34+
// after applying the changes in BinaryFragment.
35+
IsBinary bool
36+
BinaryFragment *BinaryFragment
37+
ReverseBinaryFragment *BinaryFragment
2938
}
3039

3140
// TextFragment describes changed lines starting at a specific line in a text file.
@@ -86,3 +95,18 @@ func (op LineOp) String() string {
8695
return "?"
8796
}
8897

98+
// BinaryFragment describes changes to a binary file.
99+
type BinaryFragment struct {
100+
Method BinaryPatchMethod
101+
Data []byte
102+
}
103+
104+
// BinaryPatchMethod is the method used to create and apply the binary patch.
105+
type BinaryPatchMethod int
106+
107+
const (
108+
// BinaryPatchDelta indicates the data uses Git's packfile encoding
109+
BinaryPatchDelta BinaryPatchMethod = iota
110+
// BinaryPatchLiteral indicates the data is the exact file content
111+
BinaryPatchLiteral
112+
)

gitdiff/parser.go

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func Parse(r io.Reader) ([]*File, string, error) {
3333

3434
for _, fn := range []func(*File) (int, error){
3535
p.ParseTextFragments,
36-
p.ParseBinaryFragment,
36+
p.ParseBinaryFragments,
3737
} {
3838
n, err := fn(file)
3939
if err != nil {
@@ -316,8 +316,34 @@ func (p *parser) ParseTextChunk(frag *TextFragment) error {
316316
return nil
317317
}
318318

319-
func (p *parser) ParseBinaryFragment(f *File) (n int, err error) {
320-
panic("TODO(bkeyes): unimplemented")
319+
func (p *parser) ParseBinaryFragments(f *File) (n int, err error) {
320+
isBinary, hasData, err := p.ParseBinaryMarker()
321+
if err != nil || !isBinary {
322+
return 0, err
323+
}
324+
325+
f.IsBinary = true
326+
if hasData {
327+
panic("TODO(bkeyes): unimplemented")
328+
}
329+
330+
return 0, nil
331+
}
332+
333+
func (p *parser) ParseBinaryMarker() (isBinary bool, hasData bool, err error) {
334+
switch p.Line(0) {
335+
case "GIT binary patch\n":
336+
hasData = true
337+
case "Binary files differ\n":
338+
case "Files differ\n":
339+
default:
340+
return false, false, nil
341+
}
342+
343+
if err = p.Next(); err != nil && err != io.EOF {
344+
return true, hasData, err
345+
}
346+
return true, hasData, nil
321347
}
322348

323349
func parseRange(s string) (start int64, end int64, err error) {

0 commit comments

Comments
 (0)