mercurial/patch.py
changeset 20137 9f1d4323c749
parent 20035 cd79d9ab5e42
child 20869 9658a79968c6
equal deleted inserted replaced
20136:1df77035c814 20137:9f1d4323c749
   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