Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

547 lines
15 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "tier0/platform.h"
  8. #include "tier0/dbg.h"
  9. #include "tier1/diff.h"
  10. #include "mathlib/mathlib.h"
  11. // memdbgon must be the last include file in a .cpp file!!!
  12. #include "tier0/memdbgon.h"
  13. // format of diff output:
  14. // 0NN (N=1..127) copy next N literaly
  15. //
  16. // 1NN (N=1..127) ofs (-128..127) copy next N bytes from original, changin offset by N bytes from
  17. // last copy end
  18. // 100 N ofs(-32768..32767) copy next N, with larger delta offset
  19. // 00 NNNN(1..65535) ofs(-32768..32767) big copy from old
  20. // 80 00 NN NN NN big raw copy
  21. //
  22. // available codes (could be used for additonal compression ops)
  23. // long offset form whose offset could have fit in short offset
  24. // note - this algorithm uses storage equal to 8* the old buffer size. 64k=.5mb
  25. #define MIN_MATCH_LEN 8
  26. #define ACCEPTABLE_MATCH_LEN 4096
  27. struct BlockPtr
  28. {
  29. BlockPtr *Next;
  30. uint8 const *dataptr;
  31. };
  32. template<class T,class V> static inline void AddToHead(T * & head, V * node)
  33. {
  34. node->Next=head;
  35. head=node;
  36. }
  37. void Fail(char const *msg)
  38. {
  39. Assert(0);
  40. }
  41. void ApplyDiffs(uint8 const *OldBlock, uint8 const *DiffList,
  42. int OldSize, int DiffListSize, int &ResultListSize,uint8 *Output,uint32 OutSize)
  43. {
  44. uint8 const *copy_src=OldBlock;
  45. uint8 const *end_of_diff_list=DiffList+DiffListSize;
  46. uint8 const *obuf=Output;
  47. while(DiffList<end_of_diff_list)
  48. {
  49. // printf("dptr=%x ",DiffList-d);
  50. uint8 op=*(DiffList++);
  51. if (op==0)
  52. {
  53. uint16 copy_sz=DiffList[0]+256*DiffList[1];
  54. int copy_ofs=DiffList[2]+DiffList[3]*256;
  55. if (copy_ofs>32767)
  56. copy_ofs|=0xffff0000;
  57. // printf("long cp from %x to %x len=%d\n", copy_src+copy_ofs-OldBlock,Output-obuf,copy_sz);
  58. memcpy(Output,copy_src+copy_ofs,copy_sz);
  59. Output+=copy_sz;
  60. copy_src=copy_src+copy_ofs+copy_sz;
  61. DiffList+=4;
  62. }
  63. else
  64. {
  65. if (op & 0x80)
  66. {
  67. int copy_sz=op & 0x7f;
  68. int copy_ofs;
  69. if (copy_sz==0)
  70. {
  71. copy_sz=DiffList[0];
  72. if (copy_sz==0)
  73. {
  74. // big raw copy
  75. copy_sz=DiffList[1]+256*DiffList[2]+65536*DiffList[3];
  76. memcpy(Output,DiffList+4,copy_sz);
  77. // printf("big rawcopy to %x len=%d\n", Output-obuf,copy_sz);
  78. DiffList+=copy_sz+4;
  79. Output+=copy_sz;
  80. }
  81. else
  82. {
  83. copy_ofs=DiffList[1]+(DiffList[2]*256);
  84. if (copy_ofs>32767)
  85. copy_ofs|=0xffff0000;
  86. // printf("long ofs cp from %x to %x len=%d\n", copy_src+copy_ofs-OldBlock,Output-obuf,copy_sz);
  87. memcpy(Output,copy_src+copy_ofs,copy_sz);
  88. Output+=copy_sz;
  89. copy_src=copy_src+copy_ofs+copy_sz;
  90. DiffList+=3;
  91. }
  92. }
  93. else
  94. {
  95. copy_ofs=DiffList[0];
  96. if (copy_ofs>127)
  97. copy_ofs|=0xffffff80;
  98. // printf("cp from %x to %x len=%d\n", copy_src+copy_ofs-OldBlock,Output-obuf,copy_sz);
  99. memcpy(Output,copy_src+copy_ofs,copy_sz);
  100. Output+=copy_sz;
  101. copy_src=copy_src+copy_ofs+copy_sz;
  102. DiffList++;
  103. }
  104. }
  105. else
  106. {
  107. // printf("raw copy %d to %x\n",op & 127,Output-obuf);
  108. memcpy(Output,DiffList,op & 127);
  109. Output+=op & 127;
  110. DiffList+=(op & 127);
  111. }
  112. }
  113. }
  114. ResultListSize=Output-obuf;
  115. }
  116. static void CopyPending(int len, uint8 const *rawbytes,uint8 * &outbuf, uint8 const *limit)
  117. {
  118. // printf("copy raw len=%d\n",len);
  119. if (len<128)
  120. {
  121. if (limit-outbuf < len+1)
  122. Fail("diff buffer overrun");
  123. *(outbuf++)=len;
  124. memcpy(outbuf,rawbytes,len);
  125. outbuf+=len;
  126. }
  127. else
  128. {
  129. if (limit-outbuf < len+5)
  130. Fail("diff buffer overrun");
  131. *(outbuf++)=0x80;
  132. *(outbuf++)=0x00;
  133. *(outbuf++)=(len & 255);
  134. *(outbuf++)=((len>>8) & 255);
  135. *(outbuf++)=((len>>16) & 255);
  136. memcpy(outbuf,rawbytes,len);
  137. outbuf+=len;
  138. }
  139. }
  140. static uint32 hasher(uint8 const *mdata)
  141. {
  142. // attempt to scramble the bits of h1 and h2 together
  143. uint32 ret=0;
  144. for(int i=0;i<MIN_MATCH_LEN;i++)
  145. {
  146. ret=ret<<4;
  147. ret+=(*mdata++);
  148. }
  149. return ret;
  150. }
  151. int FindDiffsForLargeFiles(uint8 const *NewBlock, uint8 const *OldBlock,
  152. int NewSize, int OldSize, int &DiffListSize,uint8 *Output,
  153. uint32 OutSize,
  154. int hashsize)
  155. {
  156. int ret=0;
  157. if (OldSize!=NewSize)
  158. ret=1;
  159. // first, build the hash table
  160. BlockPtr **HashedMatches=new BlockPtr* [hashsize];
  161. memset(HashedMatches,0,sizeof(HashedMatches[0])*hashsize);
  162. BlockPtr *Blocks=0;
  163. if (OldSize)
  164. Blocks=new BlockPtr[OldSize];
  165. BlockPtr *FreeList=Blocks;
  166. // now, build the hash table
  167. uint8 const *walk=OldBlock;
  168. if (OldBlock && OldSize)
  169. while(walk<OldBlock+OldSize-MIN_MATCH_LEN)
  170. {
  171. uint32 hash1=hasher(walk);
  172. hash1 &=(hashsize-1);
  173. BlockPtr *newnode=FreeList;
  174. FreeList++;
  175. newnode->dataptr=walk;
  176. AddToHead(HashedMatches[hash1],newnode);
  177. walk++;
  178. }
  179. else
  180. ret=1;
  181. // now, we have the hash table which may be used to search. begin the output step
  182. int pending_raw_len=0;
  183. walk=NewBlock;
  184. uint8 *outbuf=Output;
  185. uint8 const *lastmatchend=OldBlock;
  186. while(walk<NewBlock+NewSize)
  187. {
  188. int longest=0;
  189. BlockPtr *longest_block=0;
  190. if (walk<NewBlock+NewSize-MIN_MATCH_LEN)
  191. {
  192. // check for a match
  193. uint32 hash1=hasher(walk);
  194. hash1 &= (hashsize-1);
  195. // now, find the longest match in the hash table. If we find one >MIN_MATCH_LEN, take it
  196. for(BlockPtr *b=HashedMatches[hash1];b;b=b->Next)
  197. {
  198. // find the match length
  199. int match_of=b->dataptr-lastmatchend;
  200. if ((match_of>-32768) && (match_of<32767))
  201. {
  202. int max_mlength=MIN(65535,OldBlock+OldSize-b->dataptr);
  203. max_mlength=MIN(max_mlength,NewBlock+NewSize-walk);
  204. int i;
  205. for(i=0;i<max_mlength;i++)
  206. if (walk[i]!=b->dataptr[i])
  207. break;
  208. if ((i>MIN_MATCH_LEN) && (i>longest))
  209. {
  210. longest=i;
  211. longest_block=b;
  212. if (longest>ACCEPTABLE_MATCH_LEN)
  213. break;
  214. }
  215. }
  216. }
  217. }
  218. // now, we have a match maybe
  219. if (longest_block)
  220. {
  221. if (pending_raw_len) // must output
  222. {
  223. ret=1;
  224. CopyPending(pending_raw_len,walk-pending_raw_len,outbuf,Output+OutSize);
  225. pending_raw_len=0;
  226. }
  227. // now, output copy block
  228. int match_of=longest_block->dataptr-lastmatchend;
  229. int nremaining=OutSize-(outbuf-Output);
  230. if (match_of)
  231. ret=1;
  232. // printf("copy from %x to %x len=%d\n", match_of,outbuf-Output,longest);
  233. if (longest>127)
  234. {
  235. // use really long encoding
  236. if (nremaining<5)
  237. Fail("diff buff needs increase");
  238. *(outbuf++)=00;
  239. *(outbuf++)=(longest & 255);
  240. *(outbuf++)=((longest>>8) & 255);
  241. *(outbuf++)=(match_of & 255);
  242. *(outbuf++)=((match_of>>8) & 255);
  243. }
  244. else
  245. {
  246. if ((match_of>=-128) && (match_of<128))
  247. {
  248. if (nremaining<2)
  249. Fail("diff buff needs increase");
  250. *(outbuf++)=128+longest;
  251. *(outbuf++)=(match_of&255);
  252. }
  253. else
  254. {
  255. // use long encoding
  256. if (nremaining<4)
  257. Fail("diff buff needs increase");
  258. *(outbuf++)=0x80;
  259. *(outbuf++)=longest;
  260. *(outbuf++)=(match_of & 255);
  261. *(outbuf++)=((match_of>>8) & 255);
  262. }
  263. }
  264. lastmatchend=longest_block->dataptr+longest;
  265. walk+=longest;
  266. }
  267. else
  268. {
  269. walk++;
  270. pending_raw_len++;
  271. }
  272. }
  273. // now, flush pending raw copy
  274. if (pending_raw_len) // must output
  275. {
  276. ret=1;
  277. CopyPending(pending_raw_len,walk-pending_raw_len,outbuf,Output+OutSize);
  278. pending_raw_len=0;
  279. }
  280. delete[] HashedMatches;
  281. if (Blocks)
  282. delete[] Blocks;
  283. DiffListSize=outbuf-Output;
  284. return ret;
  285. }
  286. int FindDiffs(uint8 const *NewBlock, uint8 const *OldBlock,
  287. int NewSize, int OldSize, int &DiffListSize,uint8 *Output,uint32 OutSize)
  288. {
  289. int ret=0;
  290. if (OldSize!=NewSize)
  291. ret=1;
  292. // first, build the hash table
  293. BlockPtr *HashedMatches[65536];
  294. memset(HashedMatches,0,sizeof(HashedMatches));
  295. BlockPtr *Blocks=0;
  296. if (OldSize)
  297. Blocks=new BlockPtr[OldSize];
  298. BlockPtr *FreeList=Blocks;
  299. // now, build the hash table
  300. uint8 const *walk=OldBlock;
  301. if (OldBlock && OldSize)
  302. while(walk<OldBlock+OldSize-MIN_MATCH_LEN)
  303. {
  304. uint16 hash1=*((uint16 const *) walk)+*((uint16 const *) walk+2);
  305. BlockPtr *newnode=FreeList;
  306. FreeList++;
  307. newnode->dataptr=walk;
  308. AddToHead(HashedMatches[hash1],newnode);
  309. walk++;
  310. }
  311. else
  312. ret=1;
  313. // now, we have the hash table which may be used to search. begin the output step
  314. int pending_raw_len=0;
  315. walk=NewBlock;
  316. uint8 *outbuf=Output;
  317. uint8 const *lastmatchend=OldBlock;
  318. while(walk<NewBlock+NewSize)
  319. {
  320. int longest=0;
  321. BlockPtr *longest_block=0;
  322. if (walk<NewBlock+NewSize-MIN_MATCH_LEN)
  323. {
  324. // check for a match
  325. uint16 hash1=*((uint16 const *) walk)+*((uint16 const *) walk+2);
  326. // now, find the longest match in the hash table. If we find one >MIN_MATCH_LEN, take it
  327. for(BlockPtr *b=HashedMatches[hash1];b;b=b->Next)
  328. {
  329. // find the match length
  330. int match_of=b->dataptr-lastmatchend;
  331. if ((match_of>-32768) && (match_of<32767))
  332. {
  333. int max_mlength=MIN(65535,OldBlock+OldSize-b->dataptr);
  334. max_mlength=MIN(max_mlength,NewBlock+NewSize-walk);
  335. int i;
  336. for(i=0;i<max_mlength;i++)
  337. if (walk[i]!=b->dataptr[i])
  338. break;
  339. if ((i>MIN_MATCH_LEN) && (i>longest))
  340. {
  341. longest=i;
  342. longest_block=b;
  343. }
  344. }
  345. }
  346. }
  347. // now, we have a match maybe
  348. if (longest_block)
  349. {
  350. if (pending_raw_len) // must output
  351. {
  352. ret=1;
  353. CopyPending(pending_raw_len,walk-pending_raw_len,outbuf,Output+OutSize);
  354. pending_raw_len=0;
  355. }
  356. // now, output copy block
  357. int match_of=longest_block->dataptr-lastmatchend;
  358. int nremaining=OutSize-(outbuf-Output);
  359. if (match_of)
  360. ret=1;
  361. if (longest>127)
  362. {
  363. // use really long encoding
  364. if (nremaining<5)
  365. Fail("diff buff needs increase");
  366. *(outbuf++)=00;
  367. *(outbuf++)=(longest & 255);
  368. *(outbuf++)=((longest>>8) & 255);
  369. *(outbuf++)=(match_of & 255);
  370. *(outbuf++)=((match_of>>8) & 255);
  371. }
  372. else
  373. {
  374. if ((match_of>=-128) && (match_of<128))
  375. {
  376. if (nremaining<2)
  377. Fail("diff buff needs increase");
  378. *(outbuf++)=128+longest;
  379. *(outbuf++)=(match_of&255);
  380. }
  381. else
  382. {
  383. // use long encoding
  384. if (nremaining<4)
  385. Fail("diff buff needs increase");
  386. *(outbuf++)=0x80;
  387. *(outbuf++)=longest;
  388. *(outbuf++)=(match_of & 255);
  389. *(outbuf++)=((match_of>>8) & 255);
  390. }
  391. }
  392. lastmatchend=longest_block->dataptr+longest;
  393. walk+=longest;
  394. }
  395. else
  396. {
  397. walk++;
  398. pending_raw_len++;
  399. }
  400. }
  401. // now, flush pending raw copy
  402. if (pending_raw_len) // must output
  403. {
  404. ret=1;
  405. CopyPending(pending_raw_len,walk-pending_raw_len,outbuf,Output+OutSize);
  406. pending_raw_len=0;
  407. }
  408. if (Blocks)
  409. delete[] Blocks;
  410. DiffListSize=outbuf-Output;
  411. return ret;
  412. }
  413. int FindDiffsLowMemory(uint8 const *NewBlock, uint8 const *OldBlock,
  414. int NewSize, int OldSize, int &DiffListSize,uint8 *Output,uint32 OutSize)
  415. {
  416. int ret=0;
  417. if (OldSize!=NewSize)
  418. ret=1;
  419. uint8 const *old_data_hash[256];
  420. memset(old_data_hash,0,sizeof(old_data_hash));
  421. int pending_raw_len=0;
  422. uint8 const *walk=NewBlock;
  423. uint8 const *oldptr=OldBlock;
  424. uint8 *outbuf=Output;
  425. uint8 const *lastmatchend=OldBlock;
  426. while(walk<NewBlock+NewSize)
  427. {
  428. while( (oldptr-OldBlock<walk-NewBlock+40) && (oldptr-OldBlock<OldSize-MIN_MATCH_LEN))
  429. {
  430. uint16 hash1=(oldptr[0]+oldptr[1]+oldptr[2]+oldptr[3]) & (NELEMS(old_data_hash)-1);
  431. old_data_hash[hash1]=oldptr;
  432. oldptr++;
  433. }
  434. int longest=0;
  435. uint8 const *longest_block=0;
  436. if (walk<NewBlock+NewSize-MIN_MATCH_LEN)
  437. {
  438. // check for a match
  439. uint16 hash1=(walk[0]+walk[1]+walk[2]+walk[3]) & (NELEMS(old_data_hash)-1);
  440. if (old_data_hash[hash1])
  441. {
  442. int max_bytes_to_compare=MIN(NewBlock+NewSize-walk,OldBlock+OldSize-old_data_hash[hash1]);
  443. int nmatches;
  444. for(nmatches=0;nmatches<max_bytes_to_compare;nmatches++)
  445. if (walk[nmatches]!=old_data_hash[hash1][nmatches])
  446. break;
  447. if (nmatches>MIN_MATCH_LEN)
  448. {
  449. longest_block=old_data_hash[hash1];
  450. longest=nmatches;
  451. }
  452. }
  453. }
  454. // now, we have a match maybe
  455. if (longest_block)
  456. {
  457. if (pending_raw_len) // must output
  458. {
  459. ret=1;
  460. CopyPending(pending_raw_len,walk-pending_raw_len,outbuf,Output+OutSize);
  461. pending_raw_len=0;
  462. }
  463. // now, output copy block
  464. int match_of=longest_block-lastmatchend;
  465. int nremaining=OutSize-(outbuf-Output);
  466. if (match_of)
  467. ret=1;
  468. if (longest>127)
  469. {
  470. // use really long encoding
  471. if (nremaining<5)
  472. Fail("diff buff needs increase");
  473. *(outbuf++)=00;
  474. *(outbuf++)=(longest & 255);
  475. *(outbuf++)=((longest>>8) & 255);
  476. *(outbuf++)=(match_of & 255);
  477. *(outbuf++)=((match_of>>8) & 255);
  478. }
  479. else
  480. {
  481. if ((match_of>=-128) && (match_of<128))
  482. {
  483. if (nremaining<2)
  484. Fail("diff buff needs increase");
  485. *(outbuf++)=128+longest;
  486. *(outbuf++)=(match_of&255);
  487. }
  488. else
  489. {
  490. // use long encoding
  491. if (nremaining<4)
  492. Fail("diff buff needs increase");
  493. *(outbuf++)=0x80;
  494. *(outbuf++)=longest;
  495. *(outbuf++)=(match_of & 255);
  496. *(outbuf++)=((match_of>>8) & 255);
  497. }
  498. }
  499. lastmatchend=longest_block+longest;
  500. walk+=longest;
  501. }
  502. else
  503. {
  504. walk++;
  505. pending_raw_len++;
  506. }
  507. }
  508. // now, flush pending raw copy
  509. if (pending_raw_len) // must output
  510. {
  511. ret=1;
  512. CopyPending(pending_raw_len,walk-pending_raw_len,outbuf,Output+OutSize);
  513. pending_raw_len=0;
  514. }
  515. DiffListSize=outbuf-Output;
  516. return ret;
  517. }