The Labs \ Source Viewer \ SSCLI \ System.IO.Compression \ GZipDecoder

  1. //------------------------------------------------------------------------------
  2. // <copyright file="GZipDecoder.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. namespace System.IO.Compression
  16. {
  17.     using System;
  18.     using System.Diagnostics;
  19.    
  20.     internal enum GZIPHeaderState
  21.     {
  22.         // GZIP header
  23.         ReadingID1,
  24.         ReadingID2,
  25.         ReadingCM,
  26.         ReadingFLG,
  27.         ReadingMMTime,
  28.         // iterates 4 times
  29.         ReadingXFL,
  30.         ReadingOS,
  31.         ReadingXLen1,
  32.         ReadingXLen2,
  33.         ReadingXLenData,
  34.         ReadingFileName,
  35.         ReadingComment,
  36.         ReadingCRC16Part1,
  37.         ReadingCRC16Part2,
  38.         Done,
  39.         // done reading GZIP header
  40.         // GZIP footer
  41.         ReadingCRC,
  42.         // iterates 4 times
  43.         ReadingFileSize
  44.         // iterates 4 times
  45.     }
  46.    
  47.    
  48.     // This class decodes GZip header and footer information.
  49.     // See RFC 1952 for details about the format.
  50.     internal class GZipDecoder
  51.     {
  52.         const int FileText = 1;
  53.         const int CRCFlag = 2;
  54.         const int ExtraFieldsFlag = 4;
  55.         const int FileNameFlag = 8;
  56.         const int CommentFlag = 16;
  57.        
  58.         private InputBuffer input;
  59.         GZIPHeaderState gzipHeaderSubstate;
  60.         GZIPHeaderState gzipFooterSubstate;
  61.        
  62.         int gzip_header_flag;
  63.         int gzip_header_xlen;
  64.         uint gzipCrc32;
  65.         uint gzipOutputStreamSize;
  66.         int loopCounter;
  67.        
  68.         public GZipDecoder(InputBuffer input)
  69.         {
  70.             this.input = input;
  71.             Reset();
  72.         }
  73.        
  74.         public void Reset()
  75.         {
  76.             gzipHeaderSubstate = GZIPHeaderState.ReadingID1;
  77.             gzipFooterSubstate = GZIPHeaderState.ReadingCRC;
  78.             gzipCrc32 = 0;
  79.             gzipOutputStreamSize = 0;
  80.         }
  81.        
  82.         public uint Crc32 {
  83.             get { return gzipCrc32; }
  84.         }
  85.        
  86.         public uint StreamSize {
  87.             get { return gzipOutputStreamSize; }
  88.         }
  89.        
  90.        
  91.         public bool ReadGzipHeader()
  92.         {
  93.            
  94.             while (true) {
  95.                 int bits;
  96.                 switch (gzipHeaderSubstate) {
  97.                     case GZIPHeaderState.ReadingID1:
  98.                         bits = input.GetBits(8);
  99.                         if (bits < 0) {
  100.                             return false;
  101.                         }
  102.                        
  103.                         if (bits != 31) {
  104.                             throw new InvalidDataException(SR.GetString(SR.CorruptedGZipHeader));
  105.                         }
  106.                         gzipHeaderSubstate = GZIPHeaderState.ReadingID2;
  107.                         goto case GZIPHeaderState.ReadingID2;
  108.                         break;
  109.                     case GZIPHeaderState.ReadingID2:
  110.                        
  111.                         bits = input.GetBits(8);
  112.                         if (bits < 0) {
  113.                             return false;
  114.                         }
  115.                        
  116.                         if (bits != 139) {
  117.                             throw new InvalidDataException(SR.GetString(SR.CorruptedGZipHeader));
  118.                         }
  119.                        
  120.                         gzipHeaderSubstate = GZIPHeaderState.ReadingCM;
  121.                         goto case GZIPHeaderState.ReadingCM;
  122.                         break;
  123.                     case GZIPHeaderState.ReadingCM:
  124.                        
  125.                         bits = input.GetBits(8);
  126.                         if (bits < 0) {
  127.                             return false;
  128.                         }
  129.                        
  130.                         if (bits != 8) {
  131.                             // compression mode must be 8 (deflate)
  132.                             throw new InvalidDataException(SR.GetString(SR.UnknownCompressionMode));
  133.                         }
  134.                        
  135.                         gzipHeaderSubstate = GZIPHeaderState.ReadingFLG;
  136.                         ;
  137.                         goto case GZIPHeaderState.ReadingFLG;
  138.                         break;
  139.                     case GZIPHeaderState.ReadingFLG:
  140.                        
  141.                         bits = input.GetBits(8);
  142.                         if (bits < 0) {
  143.                             return false;
  144.                         }
  145.                        
  146.                         gzip_header_flag = bits;
  147.                         gzipHeaderSubstate = GZIPHeaderState.ReadingMMTime;
  148.                         loopCounter = 0;
  149.                         // 4 MMTIME bytes
  150.                         goto case GZIPHeaderState.ReadingMMTime;
  151.                         break;
  152.                     case GZIPHeaderState.ReadingMMTime:
  153.                        
  154.                         bits = 0;
  155.                         while (loopCounter < 4) {
  156.                             bits = input.GetBits(8);
  157.                             if (bits < 0) {
  158.                                 return false;
  159.                             }
  160.                            
  161.                             loopCounter++;
  162.                         }
  163.                        
  164.                         gzipHeaderSubstate = GZIPHeaderState.ReadingXFL;
  165.                         loopCounter = 0;
  166.                         goto case GZIPHeaderState.ReadingXFL;
  167.                         break;
  168.                     case GZIPHeaderState.ReadingXFL:
  169.                        
  170.                         // ignore XFL
  171.                         bits = input.GetBits(8);
  172.                         if (bits < 0) {
  173.                             return false;
  174.                         }
  175.                        
  176.                         gzipHeaderSubstate = GZIPHeaderState.ReadingOS;
  177.                         goto case GZIPHeaderState.ReadingOS;
  178.                         break;
  179.                     case GZIPHeaderState.ReadingOS:
  180.                        
  181.                         // ignore OS
  182.                         bits = input.GetBits(8);
  183.                         if (bits < 0) {
  184.                             return false;
  185.                         }
  186.                        
  187.                         gzipHeaderSubstate = GZIPHeaderState.ReadingXLen1;
  188.                         goto case GZIPHeaderState.ReadingXLen1;
  189.                         break;
  190.                     case GZIPHeaderState.ReadingXLen1:
  191.                        
  192.                         if ((gzip_header_flag & ExtraFieldsFlag) == 0) {
  193.                             goto case GZIPHeaderState.ReadingFileName;
  194.                         }
  195.                        
  196.                         bits = input.GetBits(8);
  197.                         if (bits < 0) {
  198.                             return false;
  199.                         }
  200.                        
  201.                         gzip_header_xlen = bits;
  202.                         gzipHeaderSubstate = GZIPHeaderState.ReadingXLen2;
  203.                         goto case GZIPHeaderState.ReadingXLen2;
  204.                         break;
  205.                     case GZIPHeaderState.ReadingXLen2:
  206.                        
  207.                         bits = input.GetBits(8);
  208.                         if (bits < 0) {
  209.                             return false;
  210.                         }
  211.                        
  212.                         gzip_header_xlen |= (bits << 8);
  213.                         gzipHeaderSubstate = GZIPHeaderState.ReadingXLenData;
  214.                         loopCounter = 0;
  215.                         // 0 bytes of XLEN data read so far
  216.                         goto case GZIPHeaderState.ReadingXLenData;
  217.                         break;
  218.                     case GZIPHeaderState.ReadingXLenData:
  219.                        
  220.                         bits = 0;
  221.                         while (loopCounter < gzip_header_xlen) {
  222.                             bits = input.GetBits(8);
  223.                             if (bits < 0) {
  224.                                 return false;
  225.                             }
  226.                            
  227.                             loopCounter++;
  228.                         }
  229.                         gzipHeaderSubstate = GZIPHeaderState.ReadingFileName;
  230.                         loopCounter = 0;
  231.                         goto case GZIPHeaderState.ReadingFileName;
  232.                         break;
  233.                     case GZIPHeaderState.ReadingFileName:
  234.                        
  235.                         if ((gzip_header_flag & FileNameFlag) == 0) {
  236.                             gzipHeaderSubstate = GZIPHeaderState.ReadingComment;
  237.                             goto case GZIPHeaderState.ReadingComment;
  238.                         }
  239.                        
  240.                         do {
  241.                             bits = input.GetBits(8);
  242.                             if (bits < 0) {
  243.                                 return false;
  244.                             }
  245.                            
  246.                             if (bits == 0) {
  247.                                 // see '\0' in the file name string
  248.                                 break;
  249.                             }
  250.                         }
  251.                         while (true);
  252.                        
  253.                         gzipHeaderSubstate = GZIPHeaderState.ReadingComment;
  254.                         goto case GZIPHeaderState.ReadingComment;
  255.                         break;
  256.                     case GZIPHeaderState.ReadingComment:
  257.                        
  258.                         if ((gzip_header_flag & CommentFlag) == 0) {
  259.                             gzipHeaderSubstate = GZIPHeaderState.ReadingCRC16Part1;
  260.                             goto case GZIPHeaderState.ReadingCRC16Part1;
  261.                         }
  262.                        
  263.                         do {
  264.                             bits = input.GetBits(8);
  265.                             if (bits < 0) {
  266.                                 return false;
  267.                             }
  268.                            
  269.                             if (bits == 0) {
  270.                                 // see '\0' in the file name string
  271.                                 break;
  272.                             }
  273.                         }
  274.                         while (true);
  275.                        
  276.                         gzipHeaderSubstate = GZIPHeaderState.ReadingCRC16Part1;
  277.                         goto case GZIPHeaderState.ReadingCRC16Part1;
  278.                         break;
  279.                     case GZIPHeaderState.ReadingCRC16Part1:
  280.                        
  281.                         if ((gzip_header_flag & CRCFlag) == 0) {
  282.                             gzipHeaderSubstate = GZIPHeaderState.Done;
  283.                             goto case GZIPHeaderState.Done;
  284.                         }
  285.                        
  286.                         bits = input.GetBits(8);
  287.                         // ignore crc
  288.                         if (bits < 0) {
  289.                             return false;
  290.                         }
  291.                        
  292.                         gzipHeaderSubstate = GZIPHeaderState.ReadingCRC16Part2;
  293.                         goto case GZIPHeaderState.ReadingCRC16Part2;
  294.                         break;
  295.                     case GZIPHeaderState.ReadingCRC16Part2:
  296.                        
  297.                         bits = input.GetBits(8);
  298.                         // ignore crc
  299.                         if (bits < 0) {
  300.                             return false;
  301.                         }
  302.                        
  303.                         gzipHeaderSubstate = GZIPHeaderState.Done;
  304.                         goto case GZIPHeaderState.Done;
  305.                         break;
  306.                     case GZIPHeaderState.Done:
  307.                        
  308.                         return true;
  309.                     default:
  310.                         Debug.Assert(false, "We should not reach unknown state!");
  311.                         throw new InvalidDataException(SR.GetString(SR.UnknownState));
  312.                         break;
  313.                 }
  314.             }
  315.         }
  316.        
  317.         public bool ReadGzipFooter()
  318.         {
  319.             input.SkipToByteBoundary();
  320.             if (gzipFooterSubstate == GZIPHeaderState.ReadingCRC) {
  321.                 while (loopCounter < 4) {
  322.                     int bits = input.GetBits(8);
  323.                     if (bits < 0) {
  324.                         return false;
  325.                     }
  326.                    
  327.                     gzipCrc32 |= ((uint)bits << (8 * loopCounter));
  328.                     loopCounter++;
  329.                 }
  330.                 gzipFooterSubstate = GZIPHeaderState.ReadingFileSize;
  331.                 loopCounter = 0;
  332.                
  333.             }
  334.            
  335.             if (gzipFooterSubstate == GZIPHeaderState.ReadingFileSize) {
  336.                 if (loopCounter == 0)
  337.                     gzipOutputStreamSize = 0;
  338.                
  339.                 while (loopCounter < 4) {
  340.                     int bits = input.GetBits(8);
  341.                     if (bits < 0) {
  342.                         return false;
  343.                     }
  344.                    
  345.                     gzipOutputStreamSize |= ((uint)bits << (8 * loopCounter));
  346.                     loopCounter++;
  347.                 }
  348.             }
  349.            
  350.             return true;
  351.         }
  352.     }
  353. }

Developer Fusion