Add this for backwards compatibility
[mono.git] / mcs / class / Compat.ICSharpCode.SharpZipLib / ICSharpCode.SharpZipLib / BZip2 / BZip2OutputStream.cs
1 // BZip2OutputStream.cs\r
2 // Copyright (C) 2001 Mike Krueger\r
3 //\r
4 // This program is free software; you can redistribute it and/or\r
5 // modify it under the terms of the GNU General Public License\r
6 // as published by the Free Software Foundation; either version 2\r
7 // of the License, or (at your option) any later version.\r
8 //\r
9 // This program is distributed in the hope that it will be useful,\r
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
12 // GNU General Public License for more details.\r
13 //\r
14 // You should have received a copy of the GNU General Public License\r
15 // along with this program; if not, write to the Free Software\r
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
17 //\r
18 // Linking this library statically or dynamically with other modules is\r
19 // making a combined work based on this library.  Thus, the terms and\r
20 // conditions of the GNU General Public License cover the whole\r
21 // combination.\r
22 // \r
23 // As a special exception, the copyright holders of this library give you\r
24 // permission to link this library with independent modules to produce an\r
25 // executable, regardless of the license terms of these independent\r
26 // modules, and to copy and distribute the resulting executable under\r
27 // terms of your choice, provided that you also meet, for each linked\r
28 // independent module, the terms and conditions of the license of that\r
29 // module.  An independent module is a module which is not derived from\r
30 // or based on this library.  If you modify this library, you may extend\r
31 // this exception to your version of the library, but you are not\r
32 // obligated to do so.  If you do not wish to do so, delete this\r
33 // exception statement from your version.\r
34 \r
35 using System;\r
36 using System.IO;\r
37 \r
38 using ICSharpCode.SharpZipLib.Checksums;\r
39 \r
40 namespace ICSharpCode.SharpZipLib.BZip2 \r
41 {\r
42         \r
43         /// <summary>\r
44         /// An output stream that compresses into the BZip2 format (without the file\r
45         /// header chars) into another stream.\r
46         /// TODO: Update to BZip2 1.0.1, 1.0.2\r
47         /// </summary>\r
48         public class BZip2OutputStream : Stream\r
49         {\r
50                 /// <summary>\r
51                 /// I needed to implement the abstract member.\r
52                 /// </summary>\r
53                 public override bool CanRead {\r
54                         get {\r
55                                 return baseStream.CanRead;\r
56                         }\r
57                 }\r
58                 \r
59                 /// <summary>\r
60                 /// I needed to implement the abstract member.\r
61                 /// </summary>\r
62                 public override bool CanSeek {\r
63                         get {\r
64                                 return baseStream.CanSeek;\r
65                         }\r
66                 }\r
67                 \r
68                 /// <summary>\r
69                 /// I needed to implement the abstract member.\r
70                 /// </summary>\r
71                 public override bool CanWrite {\r
72                         get {\r
73                                 return baseStream.CanWrite;\r
74                         }\r
75                 }\r
76                 \r
77                 /// <summary>\r
78                 /// I needed to implement the abstract member.\r
79                 /// </summary>\r
80                 public override long Length {\r
81                         get {\r
82                                 return baseStream.Length;\r
83                         }\r
84                 }\r
85                 \r
86                 /// <summary>\r
87                 /// I needed to implement the abstract member.\r
88                 /// </summary>\r
89                 public override long Position {\r
90                         get {\r
91                                 return baseStream.Position;\r
92                         }\r
93                         set {\r
94                                 baseStream.Position = value;\r
95                         }\r
96                 }\r
97                 \r
98                 /// <summary>\r
99                 /// I needed to implement the abstract member.\r
100                 /// </summary>\r
101                 public override long Seek(long offset, SeekOrigin origin)\r
102                 {\r
103                         return baseStream.Seek(offset, origin);\r
104                 }\r
105                 \r
106                 /// <summary>\r
107                 /// I needed to implement the abstract member.\r
108                 /// </summary>\r
109                 public override void SetLength(long val)\r
110                 {\r
111                         baseStream.SetLength(val);\r
112                 }\r
113                 \r
114                 /// <summary>\r
115                 /// I needed to implement the abstract member.\r
116                 /// </summary>\r
117                 public override int ReadByte()\r
118                 {\r
119                         return baseStream.ReadByte();\r
120                 }\r
121                 \r
122                 /// <summary>\r
123                 /// I needed to implement the abstract member.\r
124                 /// </summary>\r
125                 public override int Read(byte[] b, int off, int len)\r
126                 {\r
127                         return baseStream.Read(b, off, len);\r
128                 }\r
129                 \r
130                 public override void Write(byte[] buf, int off, int len)\r
131                 {\r
132                         for (int i = 0; i < len; ++i) {\r
133                                 WriteByte(buf[off + i]);\r
134                         }\r
135                 }\r
136                 \r
137                 readonly static int SETMASK       = (1 << 21);\r
138                 readonly static int CLEARMASK     = (~SETMASK);\r
139                 readonly static int GREATER_ICOST = 15;\r
140                 readonly static int LESSER_ICOST  = 0;\r
141                 readonly static int SMALL_THRESH  = 20;\r
142                 readonly static int DEPTH_THRESH  = 10;\r
143                 \r
144                 /*--\r
145                 If you are ever unlucky/improbable enough\r
146                 to get a stack overflow whilst sorting,\r
147                 increase the following constant and try\r
148                 again.  In practice I have never seen the\r
149                 stack go above 27 elems, so the following\r
150                 limit seems very generous.\r
151                 --*/\r
152                 readonly static int QSORT_STACK_SIZE = 1000;\r
153                 \r
154                 static void Panic() \r
155                 {\r
156                         //Console.WriteLine("panic");\r
157                 }\r
158                 \r
159                 void MakeMaps() \r
160                 {\r
161                         int i;\r
162                         nInUse = 0;\r
163                         for (i = 0; i < 256; i++) {\r
164                                 if (inUse[i]) {\r
165                                         seqToUnseq[nInUse] = (char)i;\r
166                                         unseqToSeq[i] = (char)nInUse;\r
167                                         nInUse++;\r
168                                 }\r
169                         }\r
170                 }\r
171                 \r
172                 static void HbMakeCodeLengths(char[] len, int[] freq, int alphaSize, int maxLen) \r
173                 {\r
174                         /*--\r
175                         Nodes and heap entries run from 1.  Entry 0\r
176                         for both the heap and nodes is a sentinel.\r
177                         --*/\r
178                         int nNodes, nHeap, n1, n2, j, k;\r
179                         bool  tooLong;\r
180                         \r
181                         int[] heap   = new int[BZip2Constants.MAX_ALPHA_SIZE + 2];\r
182                         int[] weight = new int[BZip2Constants.MAX_ALPHA_SIZE * 2];\r
183                         int[] parent = new int[BZip2Constants.MAX_ALPHA_SIZE * 2];\r
184                         \r
185                         for (int i = 0; i < alphaSize; ++i) {\r
186                                 weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8;\r
187                         }\r
188                         \r
189                         while (true) {\r
190                                 nNodes = alphaSize;\r
191                                 nHeap = 0;\r
192                                 \r
193                                 heap[0] = 0;\r
194                                 weight[0] = 0;\r
195                                 parent[0] = -2;\r
196                                 \r
197                                 for (int i = 1; i <= alphaSize; ++i) {\r
198                                         parent[i] = -1;\r
199                                         nHeap++;\r
200                                         heap[nHeap] = i;\r
201                                         int zz = nHeap;\r
202                                         int tmp = heap[zz];\r
203                                         while (weight[tmp] < weight[heap[zz >> 1]]) {\r
204                                                 heap[zz] = heap[zz >> 1];\r
205                                                 zz >>= 1;\r
206                                         }\r
207                                         heap[zz] = tmp;\r
208                                 }\r
209                                 if (!(nHeap < (BZip2Constants.MAX_ALPHA_SIZE+2))) {\r
210                                         Panic();\r
211                                 }\r
212                                 \r
213                                 while (nHeap > 1) {\r
214                                         n1 = heap[1];\r
215                                         heap[1] = heap[nHeap];\r
216                                         nHeap--;\r
217                                         int zz = 1;\r
218                                         int yy = 0;\r
219                                         int tmp = heap[zz];\r
220                                         while (true) {\r
221                                                 yy = zz << 1;\r
222                                                 if (yy > nHeap) {\r
223                                                         break;\r
224                                                 }\r
225                                                 if (yy < nHeap &&  weight[heap[yy+1]] < weight[heap[yy]]) {\r
226                                                         yy++;\r
227                                                 }\r
228                                                 if (weight[tmp] < weight[heap[yy]]) {\r
229                                                         break;\r
230                                                 }\r
231                                                 \r
232                                                 heap[zz] = heap[yy];\r
233                                                 zz = yy;\r
234                                         }\r
235                                         heap[zz] = tmp;\r
236                                         n2 = heap[1];\r
237                                         heap[1] = heap[nHeap];\r
238                                         nHeap--;\r
239                                         \r
240                                         zz = 1;\r
241                                         yy = 0;\r
242                                         tmp = heap[zz];\r
243                                         while (true) {\r
244                                                 yy = zz << 1;\r
245                                                 if (yy > nHeap) {\r
246                                                         break;\r
247                                                 }\r
248                                                 if (yy < nHeap && weight[heap[yy+1]] < weight[heap[yy]]) {\r
249                                                         yy++;\r
250                                                 }\r
251                                                 if (weight[tmp] < weight[heap[yy]]) {\r
252                                                         break;\r
253                                                 }\r
254                                                 heap[zz] = heap[yy];\r
255                                                 zz = yy;\r
256                                         }\r
257                                         heap[zz] = tmp;\r
258                                         nNodes++;\r
259                                         parent[n1] = parent[n2] = nNodes;\r
260                                         \r
261                                         weight[nNodes] = (int)((weight[n1] & 0xffffff00) + (weight[n2] & 0xffffff00)) | \r
262                                                          (int)(1 + (((weight[n1] & 0x000000ff) > (weight[n2] & 0x000000ff)) ? (weight[n1] & 0x000000ff) : (weight[n2] & 0x000000ff)));\r
263                                         \r
264                                         parent[nNodes] = -1;\r
265                                         nHeap++;\r
266                                         heap[nHeap] = nNodes;\r
267                                         \r
268                                         zz  = nHeap;\r
269                                         tmp = heap[zz];\r
270                                         while (weight[tmp] < weight[heap[zz >> 1]]) {\r
271                                                 heap[zz] = heap[zz >> 1];\r
272                                                 zz >>= 1;\r
273                                         }\r
274                                         heap[zz] = tmp;\r
275                                 }\r
276                                 if (!(nNodes < (BZip2Constants.MAX_ALPHA_SIZE * 2))) {\r
277                                         Panic();\r
278                                 }\r
279                                 \r
280                                 tooLong = false;\r
281                                 for (int i = 1; i <= alphaSize; ++i) {\r
282                                         j = 0;\r
283                                         k = i;\r
284                                         while (parent[k] >= 0) {\r
285                                                 k = parent[k];\r
286                                                 j++;\r
287                                         }\r
288                                         len[i - 1] = (char)j;\r
289                                         if (j > maxLen) {\r
290                                                 tooLong = true;\r
291                                         }\r
292                                 }\r
293                                 \r
294                                 if (!tooLong) {\r
295                                         break;\r
296                                 }\r
297                                 \r
298                                 for (int i = 1; i < alphaSize; ++i) {\r
299                                         j = weight[i] >> 8;\r
300                                         j = 1 + (j / 2);\r
301                                         weight[i] = j << 8;\r
302                                 }\r
303                         }\r
304                 }\r
305                 \r
306                 /*--\r
307                 index of the last char in the block, so\r
308                 the block size == last + 1.\r
309                 --*/\r
310                 int last;\r
311                 \r
312                 /*--\r
313                 index in zptr[] of original string after sorting.\r
314                 --*/\r
315                 int origPtr;\r
316                 \r
317                 /*--\r
318                 always: in the range 0 .. 9.\r
319                 The current block size is 100000 * this number.\r
320                 --*/\r
321                 int blockSize100k;\r
322                 \r
323                 bool blockRandomised;\r
324                 \r
325                 //              int bytesIn;\r
326                 int bytesOut;\r
327                 int bsBuff;\r
328                 int bsLive;\r
329                 IChecksum mCrc = new StrangeCRC();\r
330                 \r
331                 bool[] inUse = new bool[256];\r
332                 int nInUse;\r
333                 \r
334                 char[] seqToUnseq = new char[256];\r
335                 char[] unseqToSeq = new char[256];\r
336                 \r
337                 char[] selector = new char[BZip2Constants.MAX_SELECTORS];\r
338                 char[] selectorMtf = new char[BZip2Constants.MAX_SELECTORS];\r
339                 \r
340                 byte[]  block;\r
341                 int[]   quadrant;\r
342                 int[]   zptr;\r
343                 short[] szptr;\r
344                 int[]   ftab;\r
345                 \r
346                 int nMTF;\r
347                 \r
348                 int[] mtfFreq = new int[BZip2Constants.MAX_ALPHA_SIZE];\r
349                 \r
350                 /*\r
351                 * Used when sorting.  If too many long comparisons\r
352                 * happen, we stop sorting, randomise the block\r
353                 * slightly, and try again.\r
354                 */\r
355                 int workFactor;\r
356                 int workDone;\r
357                 int workLimit;\r
358                 bool firstAttempt;\r
359                 int nBlocksRandomised;\r
360                 \r
361                 int currentChar = -1;\r
362                 int runLength = 0;\r
363                 \r
364                 public BZip2OutputStream(Stream inStream) : this(inStream, 9)\r
365                 {\r
366                 }\r
367                 \r
368                 public BZip2OutputStream(Stream inStream, int inBlockSize)\r
369                 {\r
370                         block    = null;\r
371                         quadrant = null;\r
372                         zptr     = null;\r
373                         ftab     = null;\r
374                         \r
375                         BsSetStream(inStream);\r
376                         \r
377                         workFactor = 50;\r
378                         if(inBlockSize > 9) {\r
379                                 inBlockSize = 9;\r
380                         }\r
381                         if(inBlockSize < 1) {\r
382                                 inBlockSize = 1;\r
383                         }\r
384                         blockSize100k = inBlockSize;\r
385                         AllocateCompressStructures();\r
386                         Initialize();\r
387                         InitBlock();\r
388                 }\r
389                 \r
390                 public override void WriteByte(byte bv)\r
391                 {\r
392                         int b = (256 + bv) % 256;\r
393                         if (currentChar != -1) {\r
394                                 if (currentChar == b) {\r
395                                         runLength++;\r
396                                         if (runLength > 254) {\r
397                                                 WriteRun();\r
398                                                 currentChar = -1;\r
399                                                 runLength = 0;\r
400                                         }\r
401                                 } else {\r
402                                         WriteRun();\r
403                                         runLength = 1;\r
404                                         currentChar = b;\r
405                                 }\r
406                         } else {\r
407                                 currentChar = b;\r
408                                 runLength++;\r
409                         }\r
410                 }\r
411                 \r
412                 void WriteRun()\r
413                 {\r
414                         if (last < allowableBlockSize) {\r
415                                 inUse[currentChar] = true;\r
416                                 for (int i = 0; i < runLength; i++) {\r
417                                         mCrc.Update(currentChar);\r
418                                 }\r
419                                 \r
420                                 switch (runLength) {\r
421                                         case 1:\r
422                                                 last++;\r
423                                                 block[last + 1] = (byte)currentChar;\r
424                                                 break;\r
425                                         case 2:\r
426                                                 last++;\r
427                                                 block[last + 1] = (byte)currentChar;\r
428                                                 last++;\r
429                                                 block[last + 1] = (byte)currentChar;\r
430                                                 break;\r
431                                         case 3:\r
432                                                 last++;\r
433                                                 block[last + 1] = (byte)currentChar;\r
434                                                 last++;\r
435                                                 block[last + 1] = (byte)currentChar;\r
436                                                 last++;\r
437                                                 block[last + 1] = (byte)currentChar;\r
438                                                 break;\r
439                                         default:\r
440                                                 inUse[runLength - 4] = true;\r
441                                                 last++;\r
442                                                 block[last + 1] = (byte)currentChar;\r
443                                                 last++;\r
444                                                 block[last + 1] = (byte)currentChar;\r
445                                                 last++;\r
446                                                 block[last + 1] = (byte)currentChar;\r
447                                                 last++;\r
448                                                 block[last + 1] = (byte)currentChar;\r
449                                                 last++;\r
450                                                 block[last + 1] = (byte)(runLength - 4);\r
451                                                 break;\r
452                                 }\r
453                         } else {\r
454                                 EndBlock();\r
455                                 InitBlock();\r
456                                 WriteRun();\r
457                         }\r
458                 }\r
459                 \r
460                 bool closed = false;\r
461                 \r
462                 public void Finalize()\r
463                 {\r
464                         Close();\r
465                 }\r
466                 \r
467                 public override void Close()\r
468                 {\r
469                         if (closed) {\r
470                                 return;\r
471                         }\r
472                         \r
473                         if (runLength > 0) {\r
474                                 WriteRun();\r
475                         }\r
476                         \r
477                         currentChar = -1;\r
478                         EndBlock();\r
479                         EndCompression();\r
480                         closed = true;\r
481                         //                      super.close();\r
482                         Flush();\r
483                         baseStream.Close();\r
484                 }\r
485                 \r
486                 public override void Flush()\r
487                 {\r
488                         //                      super.flush();\r
489                         baseStream.Flush();\r
490                 }\r
491                 \r
492                 uint blockCRC, combinedCRC;\r
493                 \r
494                 void Initialize()\r
495                 {\r
496                         //                      bytesIn = 0;\r
497                         bytesOut = 0;\r
498                         nBlocksRandomised = 0;\r
499                         \r
500                         /*--- Write `magic' bytes h indicating file-format == huffmanised,\r
501                         followed by a digit indicating blockSize100k.\r
502                         ---*/\r
503                         BsPutUChar('B');     // -jr- 18-Nov-2003 added to match BZ2 1.02 header already in BZip class but that sux a lot\r
504                         BsPutUChar('Z');\r
505                         \r
506                         BsPutUChar('h');\r
507                         BsPutUChar('0' + blockSize100k);\r
508                         \r
509                         combinedCRC = 0;\r
510                 }\r
511                 \r
512                 int allowableBlockSize;\r
513                 \r
514                 void InitBlock() \r
515                 {\r
516                         //              blockNo++;\r
517                         mCrc.Reset();\r
518                         last = -1;\r
519                         //              ch = 0;\r
520                         \r
521                         for (int i = 0; i < 256; i++) {\r
522                                 inUse[i] = false;\r
523                         }\r
524                         \r
525                         /*--- 20 is just a paranoia constant ---*/\r
526                         allowableBlockSize = BZip2Constants.baseBlockSize * blockSize100k - 20;\r
527                 }\r
528                 \r
529                 void EndBlock()\r
530                 {\r
531                         if (last < 0) {       //-jr- dont do anything for empty files, (makes empty files compatible with original Bzip)\r
532                                 return;\r
533                         }\r
534                         \r
535                         blockCRC = (uint)mCrc.Value;\r
536                         combinedCRC = (combinedCRC << 1) | (combinedCRC >> 31);\r
537                         combinedCRC ^= blockCRC;\r
538                         \r
539                         /*-- sort the block and establish posn of original string --*/\r
540                         DoReversibleTransformation();\r
541                         \r
542                         /*--\r
543                         A 6-byte block header, the value chosen arbitrarily\r
544                         as 0x314159265359 :-).  A 32 bit value does not really\r
545                         give a strong enough guarantee that the value will not\r
546                         appear by chance in the compressed datastream.  Worst-case\r
547                         probability of this event, for a 900k block, is about\r
548                         2.0e-3 for 32 bits, 1.0e-5 for 40 bits and 4.0e-8 for 48 bits.\r
549                         For a compressed file of size 100Gb -- about 100000 blocks --\r
550                         only a 48-bit marker will do.  NB: normal compression/\r
551                         decompression do *not* rely on these statistical properties.\r
552                         They are only important when trying to recover blocks from\r
553                         damaged files.\r
554                         --*/\r
555                         BsPutUChar(0x31);\r
556                         BsPutUChar(0x41);\r
557                         BsPutUChar(0x59);\r
558                         BsPutUChar(0x26);\r
559                         BsPutUChar(0x53);\r
560                         BsPutUChar(0x59);\r
561                         \r
562                         /*-- Now the block's CRC, so it is in a known place. --*/\r
563                         BsPutint((int)blockCRC);\r
564                         \r
565                         /*-- Now a single bit indicating randomisation. --*/\r
566                         if (blockRandomised) {\r
567                                 BsW(1,1);\r
568                                 nBlocksRandomised++;\r
569                         } else {\r
570                                 BsW(1,0);\r
571                         }\r
572                         \r
573                         /*-- Finally, block's contents proper. --*/\r
574                         MoveToFrontCodeAndSend();\r
575                 }\r
576                 \r
577                 void EndCompression()\r
578                 {\r
579                         /*--\r
580                         Now another magic 48-bit number, 0x177245385090, to\r
581                         indicate the end of the last block.  (sqrt(pi), if\r
582                         you want to know.  I did want to use e, but it contains\r
583                         too much repetition -- 27 18 28 18 28 46 -- for me\r
584                         to feel statistically comfortable.  Call me paranoid.)\r
585                         --*/\r
586                         BsPutUChar(0x17);\r
587                         BsPutUChar(0x72);\r
588                         BsPutUChar(0x45);\r
589                         BsPutUChar(0x38);\r
590                         BsPutUChar(0x50);\r
591                         BsPutUChar(0x90);\r
592                         \r
593                         BsPutint((int)combinedCRC);\r
594                         \r
595                         BsFinishedWithStream();\r
596                 }\r
597                 \r
598                 void HbAssignCodes (int[] code, char[] length, int minLen, int maxLen, int alphaSize) \r
599                 {\r
600                         int vec = 0;\r
601                         for (int n = minLen; n <= maxLen; ++n) {\r
602                                 for (int i = 0; i < alphaSize; ++i) {\r
603                                         if (length[i] == n) {\r
604                                                 code[i] = vec;\r
605                                                 ++vec;\r
606                                         }\r
607                                 }\r
608                                 vec <<= 1;\r
609                         }\r
610                 }\r
611                 \r
612                 void BsSetStream(Stream f) \r
613                 {\r
614                         baseStream = f;\r
615                         bsLive = 0;\r
616                         bsBuff = 0;\r
617                         bytesOut = 0;\r
618                 }\r
619                 \r
620                 void BsFinishedWithStream()\r
621                 {\r
622                         while (bsLive > 0) \r
623                         {\r
624                                 int ch = (bsBuff >> 24);\r
625                                 baseStream.WriteByte((byte)ch); // write 8-bit\r
626                                 bsBuff <<= 8;\r
627                                 bsLive -= 8;\r
628                                 bytesOut++;\r
629                         }\r
630                 }\r
631                 \r
632                 void BsW(int n, int v)\r
633                 {\r
634                         while (bsLive >= 8) {\r
635                                 int ch = (bsBuff >> 24);\r
636                                 baseStream.WriteByte((byte)ch); // write 8-bit\r
637                                 bsBuff <<= 8;\r
638                                 bsLive -= 8;\r
639                                 ++bytesOut;\r
640                         }\r
641                         bsBuff |= (v << (32 - bsLive - n));\r
642                         bsLive += n;\r
643                 }\r
644                 \r
645                 void BsPutUChar(int c)\r
646                 {\r
647                         BsW(8, c);\r
648                 }\r
649                 \r
650                 void BsPutint(int u)\r
651                 {\r
652                         BsW(8, (u >> 24) & 0xFF);\r
653                         BsW(8, (u >> 16) & 0xFF);\r
654                         BsW(8, (u >>  8) & 0xFF);\r
655                         BsW(8,  u        & 0xFF);\r
656                 }\r
657                 \r
658                 void BsPutIntVS(int numBits, int c)\r
659                 {\r
660                         BsW(numBits, c);\r
661                 }\r
662                 \r
663                 void SendMTFValues()\r
664                 {\r
665                         char[][] len = new char[BZip2Constants.N_GROUPS][];\r
666                         for (int i = 0; i < BZip2Constants.N_GROUPS; ++i) {\r
667                                 len[i] = new char[BZip2Constants.MAX_ALPHA_SIZE];\r
668                         }\r
669                         \r
670                         int gs, ge, totc, bt, bc, iter;\r
671                         int nSelectors = 0, alphaSize, minLen, maxLen, selCtr;\r
672                         int nGroups, nBytes;\r
673                         \r
674                         alphaSize = nInUse + 2;\r
675                         for (int t = 0; t < BZip2Constants.N_GROUPS; t++) {\r
676                                 for (int v = 0; v < alphaSize; v++) {\r
677                                         len[t][v] = (char)GREATER_ICOST;\r
678                                 }\r
679                         }\r
680                         \r
681                         /*--- Decide how many coding tables to use ---*/\r
682                         if (nMTF <= 0) {\r
683                                 Panic();\r
684                         }\r
685                         \r
686                         if (nMTF < 200) {\r
687                                 nGroups = 2;\r
688                         } else if (nMTF < 600) {\r
689                                 nGroups = 3;\r
690                         } else if (nMTF < 1200) {\r
691                                 nGroups = 4;\r
692                         } else if (nMTF < 2400) {\r
693                                 nGroups = 5;\r
694                         } else {\r
695                                 nGroups = 6;\r
696                         }\r
697                         \r
698                         /*--- Generate an initial set of coding tables ---*/ \r
699                         int nPart = nGroups;\r
700                         int remF  = nMTF;\r
701                         gs = 0;\r
702                         while (nPart > 0) {\r
703                                 int tFreq = remF / nPart;\r
704                                 int aFreq = 0;\r
705                                 ge = gs - 1;\r
706                                 while (aFreq < tFreq && ge < alphaSize - 1) {\r
707                                         ge++;\r
708                                         aFreq += mtfFreq[ge];\r
709                                 }\r
710                                 \r
711                                 if (ge > gs && nPart != nGroups && nPart != 1 && ((nGroups - nPart) % 2 == 1)) {\r
712                                         aFreq -= mtfFreq[ge];\r
713                                         ge--;\r
714                                 }\r
715                                 \r
716                                 for (int v = 0; v < alphaSize; v++) {\r
717                                         if (v >= gs && v <= ge) {\r
718                                                 len[nPart - 1][v] = (char)LESSER_ICOST;\r
719                                         } else {\r
720                                                 len[nPart - 1][v] = (char)GREATER_ICOST;\r
721                                         }\r
722                                 }\r
723                                 \r
724                                 nPart--;\r
725                                 gs = ge + 1;\r
726                                 remF -= aFreq;\r
727                         }\r
728                         \r
729                         int[][] rfreq = new int[BZip2Constants.N_GROUPS][];\r
730                         for (int i = 0; i < BZip2Constants.N_GROUPS; ++i) {\r
731                                 rfreq[i] = new int[BZip2Constants.MAX_ALPHA_SIZE];\r
732                         }\r
733                         \r
734                         int[]   fave = new int[BZip2Constants.N_GROUPS];\r
735                         short[] cost = new short[BZip2Constants.N_GROUPS];\r
736                         /*---\r
737                         Iterate up to N_ITERS times to improve the tables.\r
738                         ---*/\r
739                         for (iter = 0; iter < BZip2Constants.N_ITERS; ++iter) {\r
740                                 for (int t = 0; t < nGroups; ++t) {\r
741                                         fave[t] = 0;\r
742                                 }\r
743                                 \r
744                                 for (int t = 0; t < nGroups; ++t) {\r
745                                         for (int v = 0; v < alphaSize; ++v) {\r
746                                                 rfreq[t][v] = 0;\r
747                                         }\r
748                                 }\r
749                                 \r
750                                 nSelectors = 0;\r
751                                 totc = 0;\r
752                                 gs   = 0;\r
753                                 while (true) {\r
754                                         /*--- Set group start & end marks. --*/\r
755                                         if (gs >= nMTF) {\r
756                                                 break;\r
757                                         }\r
758                                         ge = gs + BZip2Constants.G_SIZE - 1;\r
759                                         if (ge >= nMTF) {\r
760                                                 ge = nMTF - 1;\r
761                                         }\r
762                                         \r
763                                         /*--\r
764                                         Calculate the cost of this group as coded\r
765                                         by each of the coding tables.\r
766                                         --*/\r
767                                         for (int t = 0; t < nGroups; t++) {\r
768                                                 cost[t] = 0;\r
769                                         }\r
770                                         \r
771                                         if (nGroups == 6) {\r
772                                                 short cost0, cost1, cost2, cost3, cost4, cost5;\r
773                                                 cost0 = cost1 = cost2 = cost3 = cost4 = cost5 = 0;\r
774                                                 for (int i = gs; i <= ge; ++i) {\r
775                                                         short icv = szptr[i];\r
776                                                         cost0 += (short)len[0][icv];\r
777                                                         cost1 += (short)len[1][icv];\r
778                                                         cost2 += (short)len[2][icv];\r
779                                                         cost3 += (short)len[3][icv];\r
780                                                         cost4 += (short)len[4][icv];\r
781                                                         cost5 += (short)len[5][icv];\r
782                                                 }\r
783                                                 cost[0] = cost0;\r
784                                                 cost[1] = cost1;\r
785                                                 cost[2] = cost2;\r
786                                                 cost[3] = cost3;\r
787                                                 cost[4] = cost4;\r
788                                                 cost[5] = cost5;\r
789                                         } else {\r
790                                                 for (int i = gs; i <= ge; ++i) {\r
791                                                         short icv = szptr[i];\r
792                                                         for (int t = 0; t < nGroups; t++) {\r
793                                                                 cost[t] += (short)len[t][icv];\r
794                                                         }\r
795                                                 }\r
796                                         }\r
797                                         \r
798                                         /*--\r
799                                         Find the coding table which is best for this group,\r
800                                         and record its identity in the selector table.\r
801                                         --*/\r
802                                         bc = 999999999;\r
803                                         bt = -1;\r
804                                         for (int t = 0; t < nGroups; ++t) {\r
805                                                 if (cost[t] < bc) {\r
806                                                         bc = cost[t];\r
807                                                         bt = t;\r
808                                                 }\r
809                                         }\r
810                                         totc += bc;\r
811                                         fave[bt]++;\r
812                                         selector[nSelectors] = (char)bt;\r
813                                         nSelectors++;\r
814                                         \r
815                                         /*--\r
816                                         Increment the symbol frequencies for the selected table.\r
817                                         --*/\r
818                                         for (int i = gs; i <= ge; ++i) {\r
819                                                 ++rfreq[bt][szptr[i]];\r
820                                         }\r
821                                         \r
822                                         gs = ge+1;\r
823                                 }\r
824                                 \r
825                                 /*--\r
826                                 Recompute the tables based on the accumulated frequencies.\r
827                                 --*/\r
828                                 for (int t = 0; t < nGroups; ++t) {\r
829                                         HbMakeCodeLengths(len[t], rfreq[t], alphaSize, 20);\r
830                                 }\r
831                         }\r
832                         \r
833                         rfreq = null;\r
834                         fave = null;\r
835                         cost = null;\r
836                         \r
837                         if (!(nGroups < 8)) {\r
838                                 Panic();\r
839                         }\r
840                         if (!(nSelectors < 32768 && nSelectors <= (2 + (900000 / BZip2Constants.G_SIZE)))) {\r
841                                 Panic();\r
842                         }\r
843                         \r
844                         /*--- Compute MTF values for the selectors. ---*/\r
845                         char[] pos = new char[BZip2Constants.N_GROUPS];\r
846                         char ll_i, tmp2, tmp;\r
847                         for (int i = 0; i < nGroups; i++) {\r
848                                 pos[i] = (char)i;\r
849                         }\r
850                         for (int i = 0; i < nSelectors; i++) {\r
851                                 ll_i = selector[i];\r
852                                 int j = 0;\r
853                                 tmp = pos[j];\r
854                                 while (ll_i != tmp) {\r
855                                         j++;\r
856                                         tmp2 = tmp;\r
857                                         tmp = pos[j];\r
858                                         pos[j] = tmp2;\r
859                                 }\r
860                                 pos[0] = tmp;\r
861                                 selectorMtf[i] = (char)j;\r
862                         }\r
863                         \r
864                         int[][] code = new int[BZip2Constants.N_GROUPS][];\r
865                         \r
866                         for (int i = 0; i < BZip2Constants.N_GROUPS; ++i) {\r
867                                 code[i] = new int[BZip2Constants.MAX_ALPHA_SIZE];\r
868                         }\r
869                         \r
870                         /*--- Assign actual codes for the tables. --*/\r
871                         for (int t = 0; t < nGroups; t++) {\r
872                                 minLen = 32;\r
873                                 maxLen = 0;\r
874                                 for (int i = 0; i < alphaSize; i++) {\r
875                                         if (len[t][i] > maxLen) {\r
876                                                 maxLen = len[t][i];\r
877                                         }\r
878                                         if (len[t][i] < minLen) {\r
879                                                 minLen = len[t][i];\r
880                                         }\r
881                                 }\r
882                                 if (maxLen > 20) {\r
883                                         Panic();\r
884                                 }\r
885                                 if (minLen < 1) {\r
886                                         Panic();\r
887                                 }\r
888                                 HbAssignCodes(code[t], len[t], minLen, maxLen, alphaSize);\r
889                         }\r
890                         \r
891                         /*--- Transmit the mapping table. ---*/\r
892                         bool[] inUse16 = new bool[16];\r
893                         for (int i = 0; i < 16; ++i) {\r
894                                 inUse16[i] = false;\r
895                                 for (int j = 0; j < 16; ++j) {\r
896                                         if (inUse[i * 16 + j]) {\r
897                                                 inUse16[i] = true; \r
898                                         } // TODO : insert break;\r
899                                 }\r
900                         }\r
901                         \r
902                         nBytes = bytesOut;\r
903                         for (int i = 0; i < 16; ++i) {\r
904                                 if (inUse16[i]) {\r
905                                         BsW(1,1);\r
906                                 } else {\r
907                                         BsW(1,0);\r
908                                 }\r
909                         }\r
910                         \r
911                         for (int i = 0; i < 16; ++i) {\r
912                                 if (inUse16[i]) {\r
913                                         for (int j = 0; j < 16; ++j) {\r
914                                                 if (inUse[i * 16 + j]) {\r
915                                                         BsW(1,1);\r
916                                                 } else {\r
917                                                         BsW(1,0);\r
918                                                 }\r
919                                         }\r
920                                 }\r
921                         }\r
922                         \r
923                         /*--- Now the selectors. ---*/\r
924                         nBytes = bytesOut;\r
925                         BsW(3, nGroups);\r
926                         BsW(15, nSelectors);\r
927                         for (int i = 0; i < nSelectors; ++i) {\r
928                                 for (int j = 0; j < selectorMtf[i]; ++j) {\r
929                                         BsW(1,1);\r
930                                 }\r
931                                 BsW(1,0);\r
932                         }\r
933                         \r
934                         /*--- Now the coding tables. ---*/\r
935                         nBytes = bytesOut;\r
936                         \r
937                         for (int t = 0; t < nGroups; ++t) {\r
938                                 int curr = len[t][0];\r
939                                 BsW(5, curr);\r
940                                 for (int i = 0; i < alphaSize; ++i) {\r
941                                         while (curr < len[t][i]) {\r
942                                                 BsW(2, 2);\r
943                                                 curr++; /* 10 */\r
944                                         }\r
945                                         while (curr > len[t][i]) {\r
946                                                 BsW(2, 3);\r
947                                                 curr--; /* 11 */\r
948                                         }\r
949                                         BsW (1, 0);\r
950                                 }\r
951                         }\r
952                         \r
953                         /*--- And finally, the block data proper ---*/\r
954                         nBytes = bytesOut;\r
955                         selCtr = 0;\r
956                         gs = 0;\r
957                         while (true) {\r
958                                 if (gs >= nMTF) {\r
959                                         break;\r
960                                 }\r
961                                 ge = gs + BZip2Constants.G_SIZE - 1;\r
962                                 if (ge >= nMTF) {\r
963                                         ge = nMTF - 1;\r
964                                 }\r
965                                 \r
966                                 for (int i = gs; i <= ge; i++) {\r
967                                         BsW(len[selector[selCtr]][szptr[i]], code[selector[selCtr]][szptr[i]]);\r
968                                 }\r
969                                 \r
970                                 gs = ge + 1;\r
971                                 ++selCtr;\r
972                         }\r
973                         if (!(selCtr == nSelectors)) {\r
974                                 Panic();\r
975                         }\r
976                 }\r
977                 \r
978                 void MoveToFrontCodeAndSend () \r
979                 {\r
980                         BsPutIntVS(24, origPtr);\r
981                         GenerateMTFValues();\r
982                         SendMTFValues();\r
983                 }\r
984                 \r
985                 Stream baseStream;\r
986                 \r
987                 void SimpleSort(int lo, int hi, int d) \r
988                 {\r
989                         int i, j, h, bigN, hp;\r
990                         int v;\r
991                         \r
992                         bigN = hi - lo + 1;\r
993                         if (bigN < 2) {\r
994                                 return;\r
995                         }\r
996                         \r
997                         hp = 0;\r
998                         while (incs[hp] < bigN) {\r
999                                 hp++;\r
1000                         }\r
1001                         hp--;\r
1002                         \r
1003                         for (; hp >= 0; hp--) {\r
1004                                 h = incs[hp];\r
1005                                 \r
1006                                 i = lo + h;\r
1007                                 while (true) {\r
1008                                         /*-- copy 1 --*/\r
1009                                         if (i > hi)\r
1010                                                 break;\r
1011                                         v = zptr[i];\r
1012                                         j = i;\r
1013                                         while (FullGtU(zptr[j-h]+d, v+d)) {\r
1014                                                 zptr[j] = zptr[j-h];\r
1015                                                 j = j - h;\r
1016                                                 if (j <= (lo + h - 1))\r
1017                                                         break;\r
1018                                         }\r
1019                                         zptr[j] = v;\r
1020                                         i++;\r
1021                                         \r
1022                                         /*-- copy 2 --*/\r
1023                                         if (i > hi) {\r
1024                                                 break;\r
1025                                         }\r
1026                                         v = zptr[i];\r
1027                                         j = i;\r
1028                                         while (FullGtU ( zptr[j-h]+d, v+d )) {\r
1029                                                 zptr[j] = zptr[j-h];\r
1030                                                 j = j - h;\r
1031                                                 if (j <= (lo + h - 1)) {\r
1032                                                         break;\r
1033                                                 }\r
1034                                         }\r
1035                                         zptr[j] = v;\r
1036                                         i++;\r
1037                                         \r
1038                                         /*-- copy 3 --*/\r
1039                                         if (i > hi) {\r
1040                                                 break;\r
1041                                         }\r
1042                                         v = zptr[i];\r
1043                                         j = i;\r
1044                                         while (FullGtU ( zptr[j-h]+d, v+d)) {\r
1045                                                 zptr[j] = zptr[j-h];\r
1046                                                 j = j - h;\r
1047                                                 if (j <= (lo + h - 1)) {\r
1048                                                         break;\r
1049                                                 }\r
1050                                         }\r
1051                                         zptr[j] = v;\r
1052                                         i++;\r
1053                                         \r
1054                                         if (workDone > workLimit && firstAttempt) {\r
1055                                                 return;\r
1056                                         }\r
1057                                 }\r
1058                         }\r
1059                 }\r
1060                 \r
1061                 void Vswap(int p1, int p2, int n ) \r
1062                 {\r
1063                         int temp = 0;\r
1064                         while (n > 0) {\r
1065                                 temp = zptr[p1];\r
1066                                 zptr[p1] = zptr[p2];\r
1067                                 zptr[p2] = temp;\r
1068                                 p1++;\r
1069                                 p2++;\r
1070                                 n--;\r
1071                         }\r
1072                 }\r
1073                 \r
1074                 byte Med3(byte a, byte b, byte c ) \r
1075                 {\r
1076                         byte t;\r
1077                         if (a > b) {\r
1078                                 t = a;\r
1079                                 a = b;\r
1080                                 b = t;\r
1081                         }\r
1082                         if (b > c) {\r
1083                                 t = b;\r
1084                                 b = c;\r
1085                                 c = t;\r
1086                         }\r
1087                         if (a > b) {\r
1088                                 b = a;\r
1089                         }\r
1090                         return b;\r
1091                 }\r
1092                 \r
1093                 class StackElem \r
1094                 {\r
1095                         public int ll;\r
1096                         public int hh;\r
1097                         public int dd;\r
1098                 }\r
1099                 \r
1100                 void QSort3(int loSt, int hiSt, int dSt) \r
1101                 {\r
1102                         int unLo, unHi, ltLo, gtHi, med, n, m;\r
1103                         int sp, lo, hi, d;\r
1104                         StackElem[] stack = new StackElem[QSORT_STACK_SIZE];\r
1105                         for (int count = 0; count < QSORT_STACK_SIZE; count++) {\r
1106                                 stack[count] = new StackElem();\r
1107                         }\r
1108                         \r
1109                         sp = 0;\r
1110                         \r
1111                         stack[sp].ll = loSt;\r
1112                         stack[sp].hh = hiSt;\r
1113                         stack[sp].dd = dSt;\r
1114                         sp++;\r
1115                         \r
1116                         while (sp > 0) {\r
1117                                 if (sp >= QSORT_STACK_SIZE) {\r
1118                                         Panic();\r
1119                                 }\r
1120                                 \r
1121                                 sp--;\r
1122                                 lo = stack[sp].ll;\r
1123                                 hi = stack[sp].hh;\r
1124                                 d = stack[sp].dd;\r
1125                                 \r
1126                                 if (hi - lo < SMALL_THRESH || d > DEPTH_THRESH) {\r
1127                                         SimpleSort(lo, hi, d);\r
1128                                         if (workDone > workLimit && firstAttempt) {\r
1129                                                 return;\r
1130                                         }\r
1131                                         continue;\r
1132                                 }\r
1133                                 \r
1134                                 med = Med3(block[zptr[lo] + d + 1],\r
1135                                            block[zptr[hi            ] + d  + 1],\r
1136                                            block[zptr[(lo + hi) >> 1] + d + 1]);\r
1137                                 \r
1138                                 unLo = ltLo = lo;\r
1139                                 unHi = gtHi = hi;\r
1140                                 \r
1141                                 while (true) {\r
1142                                         while (true) {\r
1143                                                 if (unLo > unHi) {\r
1144                                                         break;\r
1145                                                 }\r
1146                                                 n = ((int)block[zptr[unLo]+d + 1]) - med;\r
1147                                                 if (n == 0) {\r
1148                                                         int temp = 0;\r
1149                                                         temp = zptr[unLo];\r
1150                                                         zptr[unLo] = zptr[ltLo];\r
1151                                                         zptr[ltLo] = temp;\r
1152                                                         ltLo++;\r
1153                                                         unLo++;\r
1154                                                         continue;\r
1155                                                 }\r
1156                                                 if (n >  0) {\r
1157                                                         break;\r
1158                                                 }\r
1159                                                 unLo++;\r
1160                                         }\r
1161                                         while (true) {\r
1162                                                 if (unLo > unHi) {\r
1163                                                         break;\r
1164                                                 }\r
1165                                                 n = ((int)block[zptr[unHi]+d + 1]) - med;\r
1166                                                 if (n == 0) {\r
1167                                                         int temp = 0;\r
1168                                                         temp = zptr[unHi];\r
1169                                                         zptr[unHi] = zptr[gtHi];\r
1170                                                         zptr[gtHi] = temp;\r
1171                                                         gtHi--;\r
1172                                                         unHi--;\r
1173                                                         continue;\r
1174                                                 }\r
1175                                                 if (n <  0) {\r
1176                                                         break;\r
1177                                                 }\r
1178                                                 unHi--;\r
1179                                         }\r
1180                                         if (unLo > unHi) {\r
1181                                                 break;\r
1182                                         }\r
1183                                         {\r
1184                                                 int temp = zptr[unLo];\r
1185                                                 zptr[unLo] = zptr[unHi];\r
1186                                                 zptr[unHi] = temp;\r
1187                                                 unLo++;\r
1188                                                 unHi--;\r
1189                                         }\r
1190                                 }\r
1191                                 \r
1192                                 if (gtHi < ltLo) {\r
1193                                         stack[sp].ll = lo;\r
1194                                         stack[sp].hh = hi;\r
1195                                         stack[sp].dd = d+1;\r
1196                                         sp++;\r
1197                                         continue;\r
1198                                 }\r
1199                                 \r
1200                                 n = ((ltLo-lo) < (unLo-ltLo)) ? (ltLo-lo) : (unLo-ltLo);\r
1201                                 Vswap(lo, unLo-n, n);\r
1202                                 m = ((hi-gtHi) < (gtHi-unHi)) ? (hi-gtHi) : (gtHi-unHi);\r
1203                                 Vswap(unLo, hi-m+1, m);\r
1204                                 \r
1205                                 n = lo + unLo - ltLo - 1;\r
1206                                 m = hi - (gtHi - unHi) + 1;\r
1207                                 \r
1208                                 stack[sp].ll = lo;\r
1209                                 stack[sp].hh = n;\r
1210                                 stack[sp].dd = d;\r
1211                                 sp++;\r
1212                                 \r
1213                                 stack[sp].ll = n + 1;\r
1214                                 stack[sp].hh = m - 1;\r
1215                                 stack[sp].dd = d+1;\r
1216                                 sp++;\r
1217                                 \r
1218                                 stack[sp].ll = m;\r
1219                                 stack[sp].hh = hi;\r
1220                                 stack[sp].dd = d;\r
1221                                 sp++;\r
1222                         }\r
1223                 }\r
1224                 \r
1225                 void MainSort() \r
1226                 {\r
1227                         int i, j, ss, sb;\r
1228                         int[] runningOrder = new int[256];\r
1229                         int[] copy = new int[256];\r
1230                         bool[] bigDone = new bool[256];\r
1231                         int c1, c2;\r
1232                         int numQSorted;\r
1233                         \r
1234                         /*--\r
1235                         In the various block-sized structures, live data runs\r
1236                         from 0 to last+NUM_OVERSHOOT_BYTES inclusive.  First,\r
1237                         set up the overshoot area for block.\r
1238                         --*/\r
1239                         \r
1240                         //   if (verbosity >= 4) fprintf ( stderr, "        sort initialise ...\n" );\r
1241                         for (i = 0; i < BZip2Constants.NUM_OVERSHOOT_BYTES; i++) {\r
1242                                 block[last + i + 2] = block[(i % (last + 1)) + 1];\r
1243                         }\r
1244                         for (i = 0; i <= last + BZip2Constants.NUM_OVERSHOOT_BYTES; i++) {\r
1245                                 quadrant[i] = 0;\r
1246                         }\r
1247                         \r
1248                         block[0] = (byte)(block[last + 1]);\r
1249                         \r
1250                         if (last < 4000) {\r
1251                                 /*--\r
1252                                 Use simpleSort(), since the full sorting mechanism\r
1253                                 has quite a large constant overhead.\r
1254                                 --*/\r
1255                                 for (i = 0; i <= last; i++) {\r
1256                                         zptr[i] = i;\r
1257                                 }\r
1258                                 firstAttempt = false;\r
1259                                 workDone = workLimit = 0;\r
1260                                 SimpleSort(0, last, 0);\r
1261                         } else {\r
1262                                 numQSorted = 0;\r
1263                                 for (i = 0; i <= 255; i++) {\r
1264                                         bigDone[i] = false;\r
1265                                 }\r
1266                                 for (i = 0; i <= 65536; i++) {\r
1267                                         ftab[i] = 0;\r
1268                                 }\r
1269                                 \r
1270                                 c1 = block[0];\r
1271                                 for (i = 0; i <= last; i++) {\r
1272                                         c2 = block[i + 1];\r
1273                                         ftab[(c1 << 8) + c2]++;\r
1274                                         c1 = c2;\r
1275                                 }\r
1276                                 \r
1277                                 for (i = 1; i <= 65536; i++) {\r
1278                                         ftab[i] += ftab[i - 1];\r
1279                                 }\r
1280                                 \r
1281                                 c1 = block[1];\r
1282                                 for (i = 0; i < last; i++) {\r
1283                                         c2 = block[i + 2];\r
1284                                         j = (c1 << 8) + c2;\r
1285                                         c1 = c2;\r
1286                                         ftab[j]--;\r
1287                                         zptr[ftab[j]] = i;\r
1288                                 }\r
1289                                 \r
1290                                 j = ((block[last + 1]) << 8) + (block[1]);\r
1291                                 ftab[j]--;\r
1292                                 zptr[ftab[j]] = last;\r
1293                                 \r
1294                                 /*--\r
1295                                 Now ftab contains the first loc of every small bucket.\r
1296                                 Calculate the running order, from smallest to largest\r
1297                                 big bucket.\r
1298                                 --*/\r
1299                                 \r
1300                                 for (i = 0; i <= 255; i++) {\r
1301                                         runningOrder[i] = i;\r
1302                                 }\r
1303                                 \r
1304                                 int vv;\r
1305                                 int h = 1;\r
1306                                 do {\r
1307                                         h = 3 * h + 1;\r
1308                                 } while (h <= 256);\r
1309                                 do {\r
1310                                         h = h / 3;\r
1311                                         for (i = h; i <= 255; i++) {\r
1312                                                 vv = runningOrder[i];\r
1313                                                 j = i;\r
1314                                                 while ((ftab[((runningOrder[j-h])+1) << 8] - ftab[(runningOrder[j-h]) << 8]) > (ftab[((vv)+1) << 8] - ftab[(vv) << 8])) {\r
1315                                                         runningOrder[j] = runningOrder[j-h];\r
1316                                                         j = j - h;\r
1317                                                         if (j <= (h - 1)) {\r
1318                                                                 break;\r
1319                                                         }\r
1320                                                 }\r
1321                                                 runningOrder[j] = vv;\r
1322                                         }\r
1323                                 } while (h != 1);\r
1324                                 \r
1325                                 /*--\r
1326                                 The main sorting loop.\r
1327                                 --*/\r
1328                                 for (i = 0; i <= 255; i++) {\r
1329                                         \r
1330                                         /*--\r
1331                                         Process big buckets, starting with the least full.\r
1332                                         --*/\r
1333                                         ss = runningOrder[i];\r
1334                                         \r
1335                                         /*--\r
1336                                         Complete the big bucket [ss] by quicksorting\r
1337                                         any unsorted small buckets [ss, j].  Hopefully\r
1338                                         previous pointer-scanning phases have already\r
1339                                         completed many of the small buckets [ss, j], so\r
1340                                         we don't have to sort them at all.\r
1341                                         --*/\r
1342                                         for (j = 0; j <= 255; j++) {\r
1343                                                 sb = (ss << 8) + j;\r
1344                                                 if(!((ftab[sb] & SETMASK) == SETMASK)) {\r
1345                                                         int lo = ftab[sb] & CLEARMASK;\r
1346                                                         int hi = (ftab[sb+1] & CLEARMASK) - 1;\r
1347                                                         if (hi > lo) {\r
1348                                                                 QSort3(lo, hi, 2);\r
1349                                                                 numQSorted += (hi - lo + 1);\r
1350                                                                 if (workDone > workLimit && firstAttempt) {\r
1351                                                                         return;\r
1352                                                                 }\r
1353                                                         }\r
1354                                                         ftab[sb] |= SETMASK;\r
1355                                                 }\r
1356                                         }\r
1357                                         \r
1358                                         /*--\r
1359                                         The ss big bucket is now done.  Record this fact,\r
1360                                         and update the quadrant descriptors.  Remember to\r
1361                                         update quadrants in the overshoot area too, if\r
1362                                         necessary.  The "if (i < 255)" test merely skips\r
1363                                         this updating for the last bucket processed, since\r
1364                                         updating for the last bucket is pointless.\r
1365                                         --*/\r
1366                                         bigDone[ss] = true;\r
1367                                         \r
1368                                         if (i < 255) {\r
1369                                                 int bbStart  = ftab[ss << 8] & CLEARMASK;\r
1370                                                 int bbSize   = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart;\r
1371                                                 int shifts   = 0;\r
1372                                                 \r
1373                                                 while ((bbSize >> shifts) > 65534) {\r
1374                                                         shifts++;\r
1375                                                 }\r
1376                                                 \r
1377                                                 for (j = 0; j < bbSize; j++) {\r
1378                                                         int a2update = zptr[bbStart + j];\r
1379                                                         int qVal = (j >> shifts);\r
1380                                                         quadrant[a2update] = qVal;\r
1381                                                         if (a2update < BZip2Constants.NUM_OVERSHOOT_BYTES) {\r
1382                                                                 quadrant[a2update + last + 1] = qVal;\r
1383                                                         }\r
1384                                                 }\r
1385                                                 \r
1386                                                 if (!(((bbSize-1) >> shifts) <= 65535)) {\r
1387                                                         Panic();\r
1388                                                 }\r
1389                                         }\r
1390                                         \r
1391                                         /*--\r
1392                                         Now scan this big bucket so as to synthesise the\r
1393                                         sorted order for small buckets [t, ss] for all t != ss.\r
1394                                         --*/\r
1395                                         for (j = 0; j <= 255; j++) {\r
1396                                                 copy[j] = ftab[(j << 8) + ss] & CLEARMASK;\r
1397                                         }\r
1398                                         \r
1399                                         for (j = ftab[ss << 8] & CLEARMASK; j < (ftab[(ss+1) << 8] & CLEARMASK); j++) {\r
1400                                                 c1 = block[zptr[j]];\r
1401                                                 if (!bigDone[c1]) {\r
1402                                                         zptr[copy[c1]] = zptr[j] == 0 ? last : zptr[j] - 1;\r
1403                                                         copy[c1] ++;\r
1404                                                 }\r
1405                                         }\r
1406                                         \r
1407                                         for (j = 0; j <= 255; j++) {\r
1408                                                 ftab[(j << 8) + ss] |= SETMASK;\r
1409                                         }\r
1410                                 }\r
1411                         }\r
1412                 }\r
1413                 \r
1414                 void RandomiseBlock() \r
1415                 {\r
1416                         int i;\r
1417                         int rNToGo = 0;\r
1418                         int rTPos  = 0;\r
1419                         for (i = 0; i < 256; i++) {\r
1420                                 inUse[i] = false;\r
1421                         }\r
1422                         \r
1423                         for (i = 0; i <= last; i++) {\r
1424                                 if (rNToGo == 0) {\r
1425                                         rNToGo = (int)BZip2Constants.rNums[rTPos];\r
1426                                         rTPos++;\r
1427                                         if (rTPos == 512) {\r
1428                                                 rTPos = 0;\r
1429                                         }\r
1430                                 }\r
1431                                 rNToGo--;\r
1432                                 block[i + 1] ^= (byte)((rNToGo == 1) ? 1 : 0);\r
1433                                 // handle 16 bit signed numbers\r
1434                                 block[i + 1] &= 0xFF;\r
1435                                 \r
1436                                 inUse[block[i + 1]] = true;\r
1437                         }\r
1438                 }\r
1439                 \r
1440                 void DoReversibleTransformation() \r
1441                 {\r
1442                         workLimit = workFactor * last;\r
1443                         workDone = 0;\r
1444                         blockRandomised = false;\r
1445                         firstAttempt = true;\r
1446                         \r
1447                         MainSort();\r
1448                         \r
1449                         if (workDone > workLimit && firstAttempt) {\r
1450                                 RandomiseBlock();\r
1451                                 workLimit = workDone = 0;\r
1452                                 blockRandomised = true;\r
1453                                 firstAttempt = false;\r
1454                                 MainSort();\r
1455                         }\r
1456                         \r
1457                         origPtr = -1;\r
1458                         for (int i = 0; i <= last; i++) {\r
1459                                 if (zptr[i] == 0) {\r
1460                                         origPtr = i;\r
1461                                         break;\r
1462                                 }\r
1463                         }\r
1464                         \r
1465                         if (origPtr == -1) {\r
1466                                 Panic();\r
1467                         }\r
1468                 }\r
1469                 \r
1470                 bool FullGtU(int i1, int i2) \r
1471                 {\r
1472                         int k;\r
1473                         byte c1, c2;\r
1474                         int s1, s2;\r
1475                         \r
1476                         c1 = block[i1 + 1];\r
1477                         c2 = block[i2 + 1];\r
1478                         if (c1 != c2) {\r
1479                                 return c1 > c2;\r
1480                         }\r
1481                         i1++;\r
1482                         i2++;\r
1483                         \r
1484                         c1 = block[i1 + 1];\r
1485                         c2 = block[i2 + 1];\r
1486                         if (c1 != c2) {\r
1487                                 return c1 > c2;\r
1488                         }\r
1489                         i1++;\r
1490                         i2++;\r
1491                         \r
1492                         c1 = block[i1 + 1];\r
1493                         c2 = block[i2 + 1];\r
1494                         if (c1 != c2) {\r
1495                                 return c1 > c2;\r
1496                         }\r
1497                         i1++;\r
1498                         i2++;\r
1499                         \r
1500                         c1 = block[i1 + 1];\r
1501                         c2 = block[i2 + 1];\r
1502                         if (c1 != c2) {\r
1503                                 return c1 > c2;\r
1504                         }\r
1505                         i1++;\r
1506                         i2++;\r
1507                         \r
1508                         c1 = block[i1 + 1];\r
1509                         c2 = block[i2 + 1];\r
1510                         if (c1 != c2) {\r
1511                                 return c1 > c2;\r
1512                         }\r
1513                         i1++;\r
1514                         i2++;\r
1515                         \r
1516                         c1 = block[i1 + 1];\r
1517                         c2 = block[i2 + 1];\r
1518                         if (c1 != c2) {\r
1519                                 return c1 > c2;\r
1520                         }\r
1521                         i1++;\r
1522                         i2++;\r
1523                         \r
1524                         k = last + 1;\r
1525                         \r
1526                         do {\r
1527                                 c1 = block[i1 + 1];\r
1528                                 c2 = block[i2 + 1];\r
1529                                 if (c1 != c2) {\r
1530                                         return c1 > c2;\r
1531                                 }\r
1532                                 s1 = quadrant[i1];\r
1533                                 s2 = quadrant[i2];\r
1534                                 if (s1 != s2) {\r
1535                                         return s1 > s2;\r
1536                                 }\r
1537                                 i1++;\r
1538                                 i2++;\r
1539                                 \r
1540                                 c1 = block[i1 + 1];\r
1541                                 c2 = block[i2 + 1];\r
1542                                 if (c1 != c2) {\r
1543                                         return c1 > c2;\r
1544                                 }\r
1545                                 s1 = quadrant[i1];\r
1546                                 s2 = quadrant[i2];\r
1547                                 if (s1 != s2) {\r
1548                                         return s1 > s2;\r
1549                                 }\r
1550                                 i1++;\r
1551                                 i2++;\r
1552                                 \r
1553                                 c1 = block[i1 + 1];\r
1554                                 c2 = block[i2 + 1];\r
1555                                 if (c1 != c2) {\r
1556                                         return c1 > c2;\r
1557                                 }\r
1558                                 s1 = quadrant[i1];\r
1559                                 s2 = quadrant[i2];\r
1560                                 if (s1 != s2) {\r
1561                                         return s1 > s2;\r
1562                                 }\r
1563                                 i1++;\r
1564                                 i2++;\r
1565                                 \r
1566                                 c1 = block[i1 + 1];\r
1567                                 c2 = block[i2 + 1];\r
1568                                 if (c1 != c2) {\r
1569                                         return c1 > c2;\r
1570                                 }\r
1571                                 s1 = quadrant[i1];\r
1572                                 s2 = quadrant[i2];\r
1573                                 if (s1 != s2) {\r
1574                                         return s1 > s2;\r
1575                                 }\r
1576                                 i1++;\r
1577                                 i2++;\r
1578                                 \r
1579                                 if (i1 > last) {\r
1580                                         i1 -= last;\r
1581                                         i1--;\r
1582                                 }\r
1583                                 if (i2 > last) {\r
1584                                         i2 -= last;\r
1585                                         i2--;\r
1586                                 }\r
1587                                 \r
1588                                 k -= 4;\r
1589                                 ++workDone;\r
1590                         } while (k >= 0);\r
1591                         \r
1592                         return false;\r
1593                 }\r
1594                 \r
1595                 /*--\r
1596                 Knuth's increments seem to work better\r
1597                 than Incerpi-Sedgewick here.  Possibly\r
1598                 because the number of elems to sort is\r
1599                 usually small, typically <= 20.\r
1600                 --*/\r
1601                 readonly int[] incs = new int[] { \r
1602                         1, 4, 13, 40, 121, 364, 1093, 3280,\r
1603                         9841, 29524, 88573, 265720,\r
1604                         797161, 2391484 \r
1605                 };\r
1606                 \r
1607                 void AllocateCompressStructures() \r
1608                 {\r
1609                         int n = BZip2Constants.baseBlockSize * blockSize100k;\r
1610                         block = new byte[(n + 1 + BZip2Constants.NUM_OVERSHOOT_BYTES)];\r
1611                         quadrant = new int[(n + BZip2Constants.NUM_OVERSHOOT_BYTES)];\r
1612                         zptr = new int[n];\r
1613                         ftab = new int[65537];\r
1614                         \r
1615                         if (block == null || quadrant == null || zptr == null  || ftab == null) {\r
1616                                 //              int totalDraw = (n + 1 + NUM_OVERSHOOT_BYTES) + (n + NUM_OVERSHOOT_BYTES) + n + 65537;\r
1617                                 //              compressOutOfMemory ( totalDraw, n );\r
1618                         }\r
1619                         \r
1620                         /*\r
1621                         The back end needs a place to store the MTF values\r
1622                         whilst it calculates the coding tables.  We could\r
1623                         put them in the zptr array.  However, these values\r
1624                         will fit in a short, so we overlay szptr at the\r
1625                         start of zptr, in the hope of reducing the number\r
1626                         of cache misses induced by the multiple traversals\r
1627                         of the MTF values when calculating coding tables.\r
1628                         Seems to improve compression speed by about 1%.\r
1629                         */\r
1630                         //      szptr = zptr;\r
1631                         \r
1632                         \r
1633                         szptr = new short[2 * n];\r
1634                 }\r
1635                 \r
1636                 void GenerateMTFValues() \r
1637                 {\r
1638                         char[] yy = new char[256];\r
1639                         int  i, j;\r
1640                         char tmp;\r
1641                         char tmp2;\r
1642                         int zPend;\r
1643                         int wr;\r
1644                         int EOB;\r
1645                         \r
1646                         MakeMaps();\r
1647                         EOB = nInUse+1;\r
1648                         \r
1649                         for (i = 0; i <= EOB; i++) {\r
1650                                 mtfFreq[i] = 0;\r
1651                         }\r
1652                         \r
1653                         wr = 0;\r
1654                         zPend = 0;\r
1655                         for (i = 0; i < nInUse; i++) {\r
1656                                 yy[i] = (char) i;\r
1657                         }\r
1658                         \r
1659                         \r
1660                         for (i = 0; i <= last; i++) {\r
1661                                 char ll_i;\r
1662                                 \r
1663                                 ll_i = unseqToSeq[block[zptr[i]]];\r
1664                                 \r
1665                                 j = 0;\r
1666                                 tmp = yy[j];\r
1667                                 while (ll_i != tmp) {\r
1668                                         j++;\r
1669                                         tmp2 = tmp;\r
1670                                         tmp = yy[j];\r
1671                                         yy[j] = tmp2;\r
1672                                 }\r
1673                                 yy[0] = tmp;\r
1674                                 \r
1675                                 if (j == 0) {\r
1676                                         zPend++;\r
1677                                 } else {\r
1678                                         if (zPend > 0) {\r
1679                                                 zPend--;\r
1680                                                 while (true) {\r
1681                                                         switch (zPend % 2) {\r
1682                                                                 case 0:\r
1683                                                                         szptr[wr] = (short)BZip2Constants.RUNA;\r
1684                                                                         wr++;\r
1685                                                                         mtfFreq[BZip2Constants.RUNA]++;\r
1686                                                                         break;\r
1687                                                                 case 1:\r
1688                                                                         szptr[wr] = (short)BZip2Constants.RUNB;\r
1689                                                                         wr++;\r
1690                                                                         mtfFreq[BZip2Constants.RUNB]++;\r
1691                                                                         break;\r
1692                                                         }\r
1693                                                         if (zPend < 2) {\r
1694                                                                 break;\r
1695                                                         }\r
1696                                                         zPend = (zPend - 2) / 2;\r
1697                                                 }\r
1698                                                 zPend = 0;\r
1699                                         }\r
1700                                         szptr[wr] = (short)(j + 1);\r
1701                                         wr++;\r
1702                                         mtfFreq[j + 1]++;\r
1703                                 }\r
1704                         }\r
1705                         \r
1706                         if (zPend > 0) {\r
1707                                 zPend--;\r
1708                                 while (true) {\r
1709                                         switch (zPend % 2) {\r
1710                                                 case 0:\r
1711                                                         szptr[wr] = (short)BZip2Constants.RUNA;\r
1712                                                         wr++;\r
1713                                                         mtfFreq[BZip2Constants.RUNA]++;\r
1714                                                         break;\r
1715                                                 case 1:\r
1716                                                         szptr[wr] = (short)BZip2Constants.RUNB;\r
1717                                                         wr++;\r
1718                                                         mtfFreq[BZip2Constants.RUNB]++;\r
1719                                                         break;\r
1720                                         }\r
1721                                         if (zPend < 2) {\r
1722                                                 break;\r
1723                                         }\r
1724                                         zPend = (zPend - 2) / 2;\r
1725                                 }\r
1726                         }\r
1727                         \r
1728                         szptr[wr] = (short)EOB;\r
1729                         wr++;\r
1730                         mtfFreq[EOB]++;\r
1731                         \r
1732                         nMTF = wr;\r
1733                 }\r
1734         }\r
1735 }\r
1736 \r
1737 /* This file was derived from a file containing under this license:\r
1738  * \r
1739  * This file is a part of bzip2 and/or libbzip2, a program and\r
1740  * library for lossless, block-sorting data compression.\r
1741  * \r
1742  * Copyright (C) 1996-1998 Julian R Seward.  All rights reserved.\r
1743  * \r
1744  * Redistribution and use in source and binary forms, with or without\r
1745  * modification, are permitted provided that the following conditions\r
1746  * are met:\r
1747  * \r
1748  * 1. Redistributions of source code must retain the above copyright\r
1749  * notice, this list of conditions and the following disclaimer.\r
1750  * \r
1751  * 2. The origin of this software must not be misrepresented; you must \r
1752  * not claim that you wrote the original software.  If you use this \r
1753  * software in a product, an acknowledgment in the product \r
1754  * documentation would be appreciated but is not required.\r
1755  * \r
1756  * 3. Altered source versions must be plainly marked as such, and must\r
1757  * not be misrepresented as being the original software.\r
1758  * \r
1759  * 4. The name of the author may not be used to endorse or promote \r
1760  * products derived from this software without specific prior written \r
1761  * permission.\r
1762  * \r
1763  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS\r
1764  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
1765  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
1766  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\r
1767  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
1768  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\r
1769  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
1770  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\r
1771  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
1772  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
1773  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
1774  * \r
1775  * Java version ported by Keiron Liddle, Aftex Software <keiron@aftexsw.com> 1999-2001\r
1776  */\r