PageRenderTime 43ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/main/contrib/NGit/NGit.Storage.Pack/BinaryDelta.cs

https://github.com/jfcantin/monodevelop
C# | 377 lines | 237 code | 7 blank | 133 comment | 63 complexity | 0c321d0058798b8c2f44a0ac9011fa39 MD5 | raw file
  1. /*
  2. This code is derived from jgit (http://eclipse.org/jgit).
  3. Copyright owners are documented in jgit's IP log.
  4. This program and the accompanying materials are made available
  5. under the terms of the Eclipse Distribution License v1.0 which
  6. accompanies this distribution, is reproduced below, and is
  7. available at http://www.eclipse.org/org/documents/edl-v10.php
  8. All rights reserved.
  9. Redistribution and use in source and binary forms, with or
  10. without modification, are permitted provided that the following
  11. conditions are met:
  12. - Redistributions of source code must retain the above copyright
  13. notice, this list of conditions and the following disclaimer.
  14. - Redistributions in binary form must reproduce the above
  15. copyright notice, this list of conditions and the following
  16. disclaimer in the documentation and/or other materials provided
  17. with the distribution.
  18. - Neither the name of the Eclipse Foundation, Inc. nor the
  19. names of its contributors may be used to endorse or promote
  20. products derived from this software without specific prior
  21. written permission.
  22. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  23. CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  24. INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  25. OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26. ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  27. CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  28. SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  29. NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  30. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  31. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  32. STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  33. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  34. ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  35. */
  36. using System;
  37. using System.Text;
  38. using NGit;
  39. using NGit.Storage.Pack;
  40. using NGit.Util;
  41. using Sharpen;
  42. namespace NGit.Storage.Pack
  43. {
  44. /// <summary>Recreate a stream from a base stream and a GIT pack delta.</summary>
  45. /// <remarks>
  46. /// Recreate a stream from a base stream and a GIT pack delta.
  47. /// <p>
  48. /// This entire class is heavily cribbed from <code>patch-delta.c</code> in the
  49. /// GIT project. The original delta patching code was written by Nicolas Pitre
  50. /// (&lt;nico@cam.org&gt;).
  51. /// </p>
  52. /// </remarks>
  53. public class BinaryDelta
  54. {
  55. /// <summary>Length of the base object in the delta stream.</summary>
  56. /// <remarks>Length of the base object in the delta stream.</remarks>
  57. /// <param name="delta">the delta stream, or at least the header of it.</param>
  58. /// <returns>the base object's size.</returns>
  59. public static long GetBaseSize(byte[] delta)
  60. {
  61. int p = 0;
  62. long baseLen = 0;
  63. int c;
  64. int shift = 0;
  65. do
  66. {
  67. c = delta[p++] & unchecked((int)(0xff));
  68. baseLen |= (c & unchecked((int)(0x7f))) << shift;
  69. shift += 7;
  70. }
  71. while ((c & unchecked((int)(0x80))) != 0);
  72. return baseLen;
  73. }
  74. /// <summary>Length of the resulting object in the delta stream.</summary>
  75. /// <remarks>Length of the resulting object in the delta stream.</remarks>
  76. /// <param name="delta">the delta stream, or at least the header of it.</param>
  77. /// <returns>the resulting object's size.</returns>
  78. public static long GetResultSize(byte[] delta)
  79. {
  80. int p = 0;
  81. // Skip length of the base object.
  82. //
  83. int c;
  84. do
  85. {
  86. c = delta[p++] & unchecked((int)(0xff));
  87. }
  88. while ((c & unchecked((int)(0x80))) != 0);
  89. long resLen = 0;
  90. int shift = 0;
  91. do
  92. {
  93. c = delta[p++] & unchecked((int)(0xff));
  94. resLen |= (c & unchecked((int)(0x7f))) << shift;
  95. shift += 7;
  96. }
  97. while ((c & unchecked((int)(0x80))) != 0);
  98. return resLen;
  99. }
  100. /// <summary>
  101. /// Apply the changes defined by delta to the data in base, yielding a new
  102. /// array of bytes.
  103. /// </summary>
  104. /// <remarks>
  105. /// Apply the changes defined by delta to the data in base, yielding a new
  106. /// array of bytes.
  107. /// </remarks>
  108. /// <param name="base">some byte representing an object of some kind.</param>
  109. /// <param name="delta">
  110. /// a git pack delta defining the transform from one version to
  111. /// another.
  112. /// </param>
  113. /// <returns>patched base</returns>
  114. public static byte[] Apply(byte[] @base, byte[] delta)
  115. {
  116. return Apply(@base, delta, null);
  117. }
  118. /// <summary>
  119. /// Apply the changes defined by delta to the data in base, yielding a new
  120. /// array of bytes.
  121. /// </summary>
  122. /// <remarks>
  123. /// Apply the changes defined by delta to the data in base, yielding a new
  124. /// array of bytes.
  125. /// </remarks>
  126. /// <param name="base">some byte representing an object of some kind.</param>
  127. /// <param name="delta">
  128. /// a git pack delta defining the transform from one version to
  129. /// another.
  130. /// </param>
  131. /// <param name="result">
  132. /// array to store the result into. If null the result will be
  133. /// allocated and returned.
  134. /// </param>
  135. /// <returns>
  136. /// either
  137. /// <code>result</code>
  138. /// , or the result array allocated.
  139. /// </returns>
  140. public static byte[] Apply(byte[] @base, byte[] delta, byte[] result)
  141. {
  142. int deltaPtr = 0;
  143. // Length of the base object (a variable length int).
  144. //
  145. int baseLen = 0;
  146. int c;
  147. int shift = 0;
  148. do
  149. {
  150. c = delta[deltaPtr++] & unchecked((int)(0xff));
  151. baseLen |= (c & unchecked((int)(0x7f))) << shift;
  152. shift += 7;
  153. }
  154. while ((c & unchecked((int)(0x80))) != 0);
  155. if (@base.Length != baseLen)
  156. {
  157. throw new ArgumentException(JGitText.Get().baseLengthIncorrect);
  158. }
  159. // Length of the resulting object (a variable length int).
  160. //
  161. int resLen = 0;
  162. shift = 0;
  163. do
  164. {
  165. c = delta[deltaPtr++] & unchecked((int)(0xff));
  166. resLen |= (c & unchecked((int)(0x7f))) << shift;
  167. shift += 7;
  168. }
  169. while ((c & unchecked((int)(0x80))) != 0);
  170. if (result == null)
  171. {
  172. result = new byte[resLen];
  173. }
  174. else
  175. {
  176. if (result.Length != resLen)
  177. {
  178. throw new ArgumentException(JGitText.Get().resultLengthIncorrect);
  179. }
  180. }
  181. int resultPtr = 0;
  182. while (deltaPtr < delta.Length)
  183. {
  184. int cmd = delta[deltaPtr++] & unchecked((int)(0xff));
  185. if ((cmd & unchecked((int)(0x80))) != 0)
  186. {
  187. // Determine the segment of the base which should
  188. // be copied into the output. The segment is given
  189. // as an offset and a length.
  190. //
  191. int copyOffset = 0;
  192. if ((cmd & unchecked((int)(0x01))) != 0)
  193. {
  194. copyOffset = delta[deltaPtr++] & unchecked((int)(0xff));
  195. }
  196. if ((cmd & unchecked((int)(0x02))) != 0)
  197. {
  198. copyOffset |= (delta[deltaPtr++] & unchecked((int)(0xff))) << 8;
  199. }
  200. if ((cmd & unchecked((int)(0x04))) != 0)
  201. {
  202. copyOffset |= (delta[deltaPtr++] & unchecked((int)(0xff))) << 16;
  203. }
  204. if ((cmd & unchecked((int)(0x08))) != 0)
  205. {
  206. copyOffset |= (delta[deltaPtr++] & unchecked((int)(0xff))) << 24;
  207. }
  208. int copySize = 0;
  209. if ((cmd & unchecked((int)(0x10))) != 0)
  210. {
  211. copySize = delta[deltaPtr++] & unchecked((int)(0xff));
  212. }
  213. if ((cmd & unchecked((int)(0x20))) != 0)
  214. {
  215. copySize |= (delta[deltaPtr++] & unchecked((int)(0xff))) << 8;
  216. }
  217. if ((cmd & unchecked((int)(0x40))) != 0)
  218. {
  219. copySize |= (delta[deltaPtr++] & unchecked((int)(0xff))) << 16;
  220. }
  221. if (copySize == 0)
  222. {
  223. copySize = unchecked((int)(0x10000));
  224. }
  225. System.Array.Copy(@base, copyOffset, result, resultPtr, copySize);
  226. resultPtr += copySize;
  227. }
  228. else
  229. {
  230. if (cmd != 0)
  231. {
  232. // Anything else the data is literal within the delta
  233. // itself.
  234. //
  235. System.Array.Copy(delta, deltaPtr, result, resultPtr, cmd);
  236. deltaPtr += cmd;
  237. resultPtr += cmd;
  238. }
  239. else
  240. {
  241. // cmd == 0 has been reserved for future encoding but
  242. // for now its not acceptable.
  243. //
  244. throw new ArgumentException(JGitText.Get().unsupportedCommand0);
  245. }
  246. }
  247. }
  248. return result;
  249. }
  250. /// <summary>Format this delta as a human readable string.</summary>
  251. /// <remarks>Format this delta as a human readable string.</remarks>
  252. /// <param name="delta">the delta instruction sequence to format.</param>
  253. /// <returns>the formatted delta.</returns>
  254. public static string Format(byte[] delta)
  255. {
  256. return Format(delta, true);
  257. }
  258. /// <summary>Format this delta as a human readable string.</summary>
  259. /// <remarks>Format this delta as a human readable string.</remarks>
  260. /// <param name="delta">the delta instruction sequence to format.</param>
  261. /// <param name="includeHeader">
  262. /// true if the header (base size and result size) should be
  263. /// included in the formatting.
  264. /// </param>
  265. /// <returns>the formatted delta.</returns>
  266. public static string Format(byte[] delta, bool includeHeader)
  267. {
  268. StringBuilder r = new StringBuilder();
  269. int deltaPtr = 0;
  270. long baseLen = 0;
  271. int c;
  272. int shift = 0;
  273. do
  274. {
  275. c = delta[deltaPtr++] & unchecked((int)(0xff));
  276. baseLen |= (c & unchecked((int)(0x7f))) << shift;
  277. shift += 7;
  278. }
  279. while ((c & unchecked((int)(0x80))) != 0);
  280. long resLen = 0;
  281. shift = 0;
  282. do
  283. {
  284. c = delta[deltaPtr++] & unchecked((int)(0xff));
  285. resLen |= (c & unchecked((int)(0x7f))) << shift;
  286. shift += 7;
  287. }
  288. while ((c & unchecked((int)(0x80))) != 0);
  289. if (includeHeader)
  290. {
  291. r.Append("DELTA( BASE=" + baseLen + " RESULT=" + resLen + " )\n");
  292. }
  293. while (deltaPtr < delta.Length)
  294. {
  295. int cmd = delta[deltaPtr++] & unchecked((int)(0xff));
  296. if ((cmd & unchecked((int)(0x80))) != 0)
  297. {
  298. // Determine the segment of the base which should
  299. // be copied into the output. The segment is given
  300. // as an offset and a length.
  301. //
  302. int copyOffset = 0;
  303. if ((cmd & unchecked((int)(0x01))) != 0)
  304. {
  305. copyOffset = delta[deltaPtr++] & unchecked((int)(0xff));
  306. }
  307. if ((cmd & unchecked((int)(0x02))) != 0)
  308. {
  309. copyOffset |= (delta[deltaPtr++] & unchecked((int)(0xff))) << 8;
  310. }
  311. if ((cmd & unchecked((int)(0x04))) != 0)
  312. {
  313. copyOffset |= (delta[deltaPtr++] & unchecked((int)(0xff))) << 16;
  314. }
  315. if ((cmd & unchecked((int)(0x08))) != 0)
  316. {
  317. copyOffset |= (delta[deltaPtr++] & unchecked((int)(0xff))) << 24;
  318. }
  319. int copySize = 0;
  320. if ((cmd & unchecked((int)(0x10))) != 0)
  321. {
  322. copySize = delta[deltaPtr++] & unchecked((int)(0xff));
  323. }
  324. if ((cmd & unchecked((int)(0x20))) != 0)
  325. {
  326. copySize |= (delta[deltaPtr++] & unchecked((int)(0xff))) << 8;
  327. }
  328. if ((cmd & unchecked((int)(0x40))) != 0)
  329. {
  330. copySize |= (delta[deltaPtr++] & unchecked((int)(0xff))) << 16;
  331. }
  332. if (copySize == 0)
  333. {
  334. copySize = unchecked((int)(0x10000));
  335. }
  336. r.Append(" COPY (" + copyOffset + ", " + copySize + ")\n");
  337. }
  338. else
  339. {
  340. if (cmd != 0)
  341. {
  342. // Anything else the data is literal within the delta
  343. // itself.
  344. //
  345. r.Append(" INSERT(");
  346. r.Append(QuotedString.GIT_PATH.Quote(RawParseUtils.Decode(delta, deltaPtr, deltaPtr
  347. + cmd)));
  348. r.Append(")\n");
  349. deltaPtr += cmd;
  350. }
  351. else
  352. {
  353. // cmd == 0 has been reserved for future encoding but
  354. // for now its not acceptable.
  355. //
  356. throw new ArgumentException(JGitText.Get().unsupportedCommand0);
  357. }
  358. }
  359. }
  360. return r.ToString();
  361. }
  362. }
  363. }