719 |
719 |
720 if isinstance(h, binhunk): |
720 if isinstance(h, binhunk): |
721 if self.remove: |
721 if self.remove: |
722 self.backend.unlink(self.fname) |
722 self.backend.unlink(self.fname) |
723 else: |
723 else: |
724 self.lines[:] = h.new() |
724 l = h.new(self.lines) |
725 self.offset += len(h.new()) |
725 self.lines[:] = l |
|
726 self.offset += len(l) |
726 self.dirty = True |
727 self.dirty = True |
727 return 0 |
728 return 0 |
728 |
729 |
729 horig = h |
730 horig = h |
730 if (self.eolmode in ('crlf', 'lf') |
731 if (self.eolmode in ('crlf', 'lf') |
1014 if self.lenb and newstart > 0: |
1015 if self.lenb and newstart > 0: |
1015 newstart -= 1 |
1016 newstart -= 1 |
1016 return old, oldstart, new, newstart |
1017 return old, oldstart, new, newstart |
1017 |
1018 |
1018 class binhunk(object): |
1019 class binhunk(object): |
1019 'A binary patch file. Only understands literals so far.' |
1020 'A binary patch file.' |
1020 def __init__(self, lr, fname): |
1021 def __init__(self, lr, fname): |
1021 self.text = None |
1022 self.text = None |
|
1023 self.delta = False |
1022 self.hunk = ['GIT binary patch\n'] |
1024 self.hunk = ['GIT binary patch\n'] |
1023 self._fname = fname |
1025 self._fname = fname |
1024 self._read(lr) |
1026 self._read(lr) |
1025 |
1027 |
1026 def complete(self): |
1028 def complete(self): |
1027 return self.text is not None |
1029 return self.text is not None |
1028 |
1030 |
1029 def new(self): |
1031 def new(self, lines): |
|
1032 if self.delta: |
|
1033 return [applybindelta(self.text, ''.join(lines))] |
1030 return [self.text] |
1034 return [self.text] |
1031 |
1035 |
1032 def _read(self, lr): |
1036 def _read(self, lr): |
1033 def getline(lr, hunk): |
1037 def getline(lr, hunk): |
1034 l = lr.readline() |
1038 l = lr.readline() |
1035 hunk.append(l) |
1039 hunk.append(l) |
1036 return l.rstrip('\r\n') |
1040 return l.rstrip('\r\n') |
1037 |
1041 |
|
1042 size = 0 |
1038 while True: |
1043 while True: |
1039 line = getline(lr, self.hunk) |
1044 line = getline(lr, self.hunk) |
1040 if not line: |
1045 if not line: |
1041 raise PatchError(_('could not extract "%s" binary data') |
1046 raise PatchError(_('could not extract "%s" binary data') |
1042 % self._fname) |
1047 % self._fname) |
1043 if line.startswith('literal '): |
1048 if line.startswith('literal '): |
|
1049 size = int(line[8:].rstrip()) |
1044 break |
1050 break |
1045 size = int(line[8:].rstrip()) |
1051 if line.startswith('delta '): |
|
1052 size = int(line[6:].rstrip()) |
|
1053 self.delta = True |
|
1054 break |
1046 dec = [] |
1055 dec = [] |
1047 line = getline(lr, self.hunk) |
1056 line = getline(lr, self.hunk) |
1048 while len(line) > 1: |
1057 while len(line) > 1: |
1049 l = line[0] |
1058 l = line[0] |
1050 if l <= 'Z' and l >= 'A': |
1059 if l <= 'Z' and l >= 'A': |
1262 hunknum = 0 |
1271 hunknum = 0 |
1263 |
1272 |
1264 while gitpatches: |
1273 while gitpatches: |
1265 gp = gitpatches.pop() |
1274 gp = gitpatches.pop() |
1266 yield 'file', ('a/' + gp.path, 'b/' + gp.path, None, gp.copy()) |
1275 yield 'file', ('a/' + gp.path, 'b/' + gp.path, None, gp.copy()) |
|
1276 |
|
1277 def applybindelta(binchunk, data): |
|
1278 """Apply a binary delta hunk |
|
1279 The algorithm used is the algorithm from git's patch-delta.c |
|
1280 """ |
|
1281 def deltahead(binchunk): |
|
1282 i = 0 |
|
1283 for c in binchunk: |
|
1284 i += 1 |
|
1285 if not (ord(c) & 0x80): |
|
1286 return i |
|
1287 return i |
|
1288 out = "" |
|
1289 s = deltahead(binchunk) |
|
1290 binchunk = binchunk[s:] |
|
1291 s = deltahead(binchunk) |
|
1292 binchunk = binchunk[s:] |
|
1293 i = 0 |
|
1294 while i < len(binchunk): |
|
1295 cmd = ord(binchunk[i]) |
|
1296 i += 1 |
|
1297 if (cmd & 0x80): |
|
1298 offset = 0 |
|
1299 size = 0 |
|
1300 if (cmd & 0x01): |
|
1301 offset = ord(binchunk[i]) |
|
1302 i += 1 |
|
1303 if (cmd & 0x02): |
|
1304 offset |= ord(binchunk[i]) << 8 |
|
1305 i += 1 |
|
1306 if (cmd & 0x04): |
|
1307 offset |= ord(binchunk[i]) << 16 |
|
1308 i += 1 |
|
1309 if (cmd & 0x08): |
|
1310 offset |= ord(binchunk[i]) << 24 |
|
1311 i += 1 |
|
1312 if (cmd & 0x10): |
|
1313 size = ord(binchunk[i]) |
|
1314 i += 1 |
|
1315 if (cmd & 0x20): |
|
1316 size |= ord(binchunk[i]) << 8 |
|
1317 i += 1 |
|
1318 if (cmd & 0x40): |
|
1319 size |= ord(binchunk[i]) << 16 |
|
1320 i += 1 |
|
1321 if size == 0: |
|
1322 size = 0x10000 |
|
1323 offset_end = offset + size |
|
1324 out += data[offset:offset_end] |
|
1325 elif cmd != 0: |
|
1326 offset_end = i + cmd |
|
1327 out += binchunk[i:offset_end] |
|
1328 i += cmd |
|
1329 else: |
|
1330 raise PatchError(_('unexpected delta opcode 0')) |
|
1331 return out |
1267 |
1332 |
1268 def applydiff(ui, fp, backend, store, strip=1, eolmode='strict'): |
1333 def applydiff(ui, fp, backend, store, strip=1, eolmode='strict'): |
1269 """Reads a patch from fp and tries to apply it. |
1334 """Reads a patch from fp and tries to apply it. |
1270 |
1335 |
1271 Returns 0 for a clean patch, -1 if any rejects were found and 1 if |
1336 Returns 0 for a clean patch, -1 if any rejects were found and 1 if |