home *** CD-ROM | disk | FTP | other *** search
/ Computer Active 2010 August / CA08.iso / Multimedija / shufflr.air / ShufflrClient.swf / scripts / air / update / core / UCFUnpackager.as < prev    next >
Encoding:
Text File  |  2010-06-23  |  20.4 KB  |  525 lines

  1. package air.update.core
  2. {
  3.    import air.update.states.HSM;
  4.    import air.update.states.HSMEvent;
  5.    import air.update.utils.Constants;
  6.    import flash.events.*;
  7.    import flash.filesystem.*;
  8.    import flash.net.*;
  9.    import flash.utils.*;
  10.    
  11.    public class UCFUnpackager extends HSM
  12.    {
  13.       protected static const AT_START:uint = 0;
  14.       
  15.       protected static const AT_HEADER:uint = 1;
  16.       
  17.       protected static const AT_FILENAME:uint = 2;
  18.       
  19.       protected static const AT_EXTRA_FIELD:uint = 3;
  20.       
  21.       protected static const AT_DATA:uint = 4;
  22.       
  23.       protected static const AT_END:uint = 5;
  24.       
  25.       protected static const AT_ERROR:uint = 6;
  26.       
  27.       protected static const AT_COMPLETE:uint = 12;
  28.       
  29.       protected static const AT_ABORTED:uint = 13;
  30.       
  31.       protected static const AT_CDHEADER:uint = 7;
  32.       
  33.       protected static const AT_CDHEADERMAGIC:uint = 8;
  34.       
  35.       protected static const AT_CDFILENAME:uint = 9;
  36.       
  37.       protected static const AT_CDEXTRA_FIELD:uint = 10;
  38.       
  39.       protected static const AT_CDCOMMENT:uint = 11;
  40.       
  41.       private var m_validator:Object = new Object();
  42.       
  43.       private var m_ucfParseState:uint = 0;
  44.       
  45.       private var _data:ByteArray;
  46.       
  47.       private var _path:String;
  48.       
  49.       private var _fileCommentLength:uint;
  50.       
  51.       private var m_isComplete:Boolean = false;
  52.       
  53.       private var source:URLStream;
  54.       
  55.       private var m_fileCount:uint = 0;
  56.       
  57.       private var _currentLFH:ByteArray;
  58.       
  59.       private var _extraFieldLength:uint;
  60.       
  61.       private var identifier:String;
  62.       
  63.       private var _fileRelativeOffset:uint;
  64.       
  65.       private var m_dir:File;
  66.       
  67.       private var _root:Object = new Object();
  68.       
  69.       private var _compressedSize:uint;
  70.       
  71.       private var _generalPurposeBitFlags:uint;
  72.       
  73.       private var _uncompressedSize:uint;
  74.       
  75.       private var isDirectory:Boolean;
  76.       
  77.       private var _compressionMethod:uint;
  78.       
  79.       private var _filenameLength:uint;
  80.       
  81.       private var m_enableSignatureValidation:Boolean = false;
  82.       
  83.       public function UCFUnpackager()
  84.       {
  85.          super(this.initialized);
  86.       }
  87.       
  88.       protected function onDone() : void
  89.       {
  90.       }
  91.       
  92.       public function get isComplete() : Boolean
  93.       {
  94.          return this.m_isComplete;
  95.       }
  96.       
  97.       private function unpackaging(param1:Event) : void
  98.       {
  99.          switch(param1.type)
  100.          {
  101.             case HSMEvent.ENTER:
  102.                this.source = new URLStream();
  103.                this.source.endian = Endian.LITTLE_ENDIAN;
  104.                this.source.addEventListener(ProgressEvent.PROGRESS,dispatch);
  105.                this.source.addEventListener(HTTPStatusEvent.HTTP_STATUS,dispatch);
  106.                this.source.addEventListener(IOErrorEvent.IO_ERROR,dispatch);
  107.                this.source.addEventListener(SecurityErrorEvent.SECURITY_ERROR,dispatch);
  108.                this.source.addEventListener(Event.COMPLETE,dispatch);
  109.                this.source.load(new URLRequest(this.identifier));
  110.                break;
  111.             case ProgressEvent.PROGRESS:
  112.                this.onData(param1 as ProgressEvent);
  113.                break;
  114.             case HTTPStatusEvent.HTTP_STATUS:
  115.                dispatchEvent(param1.clone());
  116.                break;
  117.             case IOErrorEvent.IO_ERROR:
  118.             case SecurityErrorEvent.SECURITY_ERROR:
  119.                this.m_ucfParseState = AT_ERROR;
  120.                dispatchEvent(param1.clone());
  121.                break;
  122.             case Event.COMPLETE:
  123.                this.onComplete(param1);
  124.          }
  125.       }
  126.       
  127.       public function set enableSignatureValidation(param1:Boolean) : void
  128.       {
  129.          this.m_enableSignatureValidation = param1;
  130.       }
  131.       
  132.       private function errored(param1:Event) : void
  133.       {
  134.       }
  135.       
  136.       private function onData(param1:ProgressEvent) : void
  137.       {
  138.          var HEADER_SIZE_BYTES:uint = 0;
  139.          var ZIP_LFH_MAGIC:uint = 0;
  140.          var CDHEADER_SIZE_BYTES:uint = 0;
  141.          var ZIP_CDH_MAGIC:uint = 0;
  142.          var ZIP_CDSIG_MAGIC:uint = 0;
  143.          var magic:uint = 0;
  144.          var filename:ByteArray = null;
  145.          var versionNeededToExtract:uint = 0;
  146.          var lastModTime:uint = 0;
  147.          var lastModDate:uint = 0;
  148.          var crc32:uint = 0;
  149.          var DATA_DESCRIPTOR_FLAG:uint = 0;
  150.          var COMPRESSION_NONE:uint = 0;
  151.          var COMPRESSION_DEFLATE:uint = 0;
  152.          var elements:Array = null;
  153.          var numParentDirs:int = 0;
  154.          var parent:Object = null;
  155.          var currentPath:Array = null;
  156.          var sizeToRead:uint = 0;
  157.          var i:uint = 0;
  158.          var element:String = null;
  159.          var shouldContinue:Boolean = false;
  160.          var fs:FileStream = null;
  161.          var event:ProgressEvent = param1;
  162.          dispatchEvent(event.clone());
  163.          try
  164.          {
  165.             HEADER_SIZE_BYTES = 30;
  166.             ZIP_LFH_MAGIC = 67324752;
  167.             CDHEADER_SIZE_BYTES = 46;
  168.             ZIP_CDH_MAGIC = 33639248;
  169.             ZIP_CDSIG_MAGIC = 101010256;
  170.             loop0:
  171.             while(true)
  172.             {
  173.                switch(this.m_ucfParseState)
  174.                {
  175.                   case AT_START:
  176.                   case AT_HEADER:
  177.                      if(this.source.bytesAvailable < HEADER_SIZE_BYTES)
  178.                      {
  179.                         break loop0;
  180.                      }
  181.                      this._currentLFH = new ByteArray();
  182.                      this._currentLFH.endian = Endian.LITTLE_ENDIAN;
  183.                      this.source.readBytes(this._currentLFH,0,4);
  184.                      magic = this._currentLFH.readUnsignedInt();
  185.                      if(ZIP_LFH_MAGIC != magic)
  186.                      {
  187.                         if(this.m_ucfParseState == AT_START)
  188.                         {
  189.                            throw new Error("not an AIR file",Constants.ERROR_UCF_INVALID_AIR_FILE);
  190.                         }
  191.                         if(ZIP_CDH_MAGIC != magic)
  192.                         {
  193.                            this.m_ucfParseState = AT_END;
  194.                            return;
  195.                         }
  196.                         this.m_ucfParseState = AT_CDHEADERMAGIC;
  197.                         continue;
  198.                      }
  199.                      this.source.readBytes(this._currentLFH,this._currentLFH.length,HEADER_SIZE_BYTES - 4);
  200.                      versionNeededToExtract = this._currentLFH.readUnsignedShort();
  201.                      this._generalPurposeBitFlags = this._currentLFH.readUnsignedShort();
  202.                      if((this._generalPurposeBitFlags & 0xFFF9) != 0)
  203.                      {
  204.                         throw new Error("file uses unsupported encryption or streaming features",Constants.ERROR_UCF_INVALID_FLAGS);
  205.                      }
  206.                      this._compressionMethod = this._currentLFH.readUnsignedShort();
  207.                      lastModTime = this._currentLFH.readUnsignedShort();
  208.                      lastModDate = this._currentLFH.readUnsignedShort();
  209.                      crc32 = this._currentLFH.readUnsignedInt();
  210.                      this._compressedSize = this._currentLFH.readUnsignedInt();
  211.                      this._uncompressedSize = this._currentLFH.readUnsignedInt();
  212.                      this._filenameLength = this._currentLFH.readUnsignedShort();
  213.                      this._extraFieldLength = this._currentLFH.readUnsignedShort();
  214.                      if(this._filenameLength == 0)
  215.                      {
  216.                         throw new Error("one of the files has an empty (zero-length) name",Constants.ERROR_UCF_INVALID_FILENAME);
  217.                      }
  218.                      this.m_ucfParseState = AT_FILENAME;
  219.                   case AT_FILENAME:
  220.                      if(this.source.bytesAvailable < this._filenameLength)
  221.                      {
  222.                         return;
  223.                      }
  224.                      this.source.readBytes(this._currentLFH,this._currentLFH.length,this._filenameLength);
  225.                      filename = new ByteArray();
  226.                      this._currentLFH.readBytes(filename,0,this._filenameLength);
  227.                      this._path = filename.toString();
  228.                      if(this.m_fileCount == 0 && this._path != "mimetype")
  229.                      {
  230.                         throw new Error("mimetype must be the first file",Constants.ERROR_UCF_NO_MIMETYPE);
  231.                      }
  232.                      DATA_DESCRIPTOR_FLAG = 128;
  233.                      if(this._generalPurposeBitFlags & DATA_DESCRIPTOR_FLAG)
  234.                      {
  235.                         throw new Error("file " + this._path + " uses a data descriptor field",Constants.ERROR_UCF_INVALID_FLAGS);
  236.                      }
  237.                      COMPRESSION_NONE = 0;
  238.                      COMPRESSION_DEFLATE = 8;
  239.                      if(this._compressionMethod != COMPRESSION_DEFLATE && this._compressionMethod != COMPRESSION_NONE)
  240.                      {
  241.                         throw new Error("file " + this._path + " uses an illegal compression method " + this._compressionMethod,Constants.ERROR_UCF_UNKNOWN_COMPRESSION);
  242.                      }
  243.                      this.isDirectory = this._path.charAt(this._path.length - 1) == "/";
  244.                      if(this.isDirectory)
  245.                      {
  246.                         this._path = this._path.slice(0,this._path.length - 1);
  247.                      }
  248.                      elements = this._path.split("/");
  249.                      if(elements.length == 0)
  250.                      {
  251.                         throw new Error("it contains a file with an empty name",Constants.ERROR_UCF_INVALID_FILENAME);
  252.                      }
  253.                      elements.filter(function(param1:*, param2:int, param3:Array):Boolean
  254.                      {
  255.                         if(param1 == ".")
  256.                         {
  257.                            throw new Error("filename " + _path + " contains a component of \'.\'",Constants.ERROR_UCF_INVALID_FILENAME);
  258.                         }
  259.                         if(param1 == "..")
  260.                         {
  261.                            throw new Error("filename " + _path + " contains a component of \'..\'",Constants.ERROR_UCF_INVALID_FILENAME);
  262.                         }
  263.                         if(param1 == "")
  264.                         {
  265.                            throw new Error("filename " + _path + " contains an empty component",Constants.ERROR_UCF_INVALID_FILENAME);
  266.                         }
  267.                         return true;
  268.                      });
  269.                      numParentDirs = this.isDirectory ? int(elements.length) : int(elements.length - 1);
  270.                      parent = this._root;
  271.                      currentPath = new Array();
  272.                      i = 0;
  273.                      while(i < numParentDirs)
  274.                      {
  275.                         element = elements[i];
  276.                         currentPath.push(element);
  277.                         if(parent[element] == null)
  278.                         {
  279.                            parent[element] = new Object();
  280.                            this.onDirectory(currentPath.join("/"));
  281.                         }
  282.                         parent = parent[element];
  283.                         i++;
  284.                      }
  285.                      this.m_ucfParseState = AT_EXTRA_FIELD;
  286.                   case AT_EXTRA_FIELD:
  287.                      if(this.source.bytesAvailable < this._extraFieldLength)
  288.                      {
  289.                         return;
  290.                      }
  291.                      if(this._extraFieldLength > 0)
  292.                      {
  293.                         this.source.readBytes(this._currentLFH,this._currentLFH.length,this._extraFieldLength);
  294.                      }
  295.                      this.m_ucfParseState = AT_DATA;
  296.                   case AT_DATA:
  297.                      sizeToRead = this._compressionMethod == 8 ? this._compressedSize : this._uncompressedSize;
  298.                      if(this.source.bytesAvailable < sizeToRead)
  299.                      {
  300.                         return;
  301.                      }
  302.                      if(this.isDirectory)
  303.                      {
  304.                         if(this._uncompressedSize != 0)
  305.                         {
  306.                            throw new Error("directory entry " + this._path + " has associated data",Constants.ERROR_UCF_INVALID_FILENAME);
  307.                         }
  308.                         if(this.m_dir)
  309.                         {
  310.                            this.m_dir.resolvePath(this._path).createDirectory();
  311.                         }
  312.                      }
  313.                      else
  314.                      {
  315.                         this._data = new ByteArray();
  316.                         if(sizeToRead > 0)
  317.                         {
  318.                            this.source.readBytes(this._data,0,sizeToRead);
  319.                            if(this._compressionMethod == 8)
  320.                            {
  321.                               this._data.uncompress(CompressionAlgorithm.DEFLATE);
  322.                            }
  323.                         }
  324.                         if(this.m_dir)
  325.                         {
  326.                            this._data.position = 0;
  327.                            fs = new FileStream();
  328.                            fs.open(this.m_dir.resolvePath(this._path),FileMode.WRITE);
  329.                            fs.writeBytes(this._data);
  330.                            fs.close();
  331.                         }
  332.                         if(this.m_enableSignatureValidation)
  333.                         {
  334.                            if(this._path == "META-INF/signatures.xml")
  335.                            {
  336.                               this.m_validator.signatures = this._data;
  337.                            }
  338.                            else
  339.                            {
  340.                               this.m_validator.addFile(this._path,this._data);
  341.                            }
  342.                         }
  343.                         shouldContinue = this.onFile(this.m_fileCount,this._path,this._data);
  344.                         if(!shouldContinue)
  345.                         {
  346.                            this.m_ucfParseState = AT_ABORTED;
  347.                            continue;
  348.                         }
  349.                      }
  350.                      ++this.m_fileCount;
  351.                      this.m_ucfParseState = AT_HEADER;
  352.                      break;
  353.                   case AT_CDHEADER:
  354.                      if(this.source.bytesAvailable < 4)
  355.                      {
  356.                         return;
  357.                      }
  358.                      this._currentLFH = new ByteArray();
  359.                      this._currentLFH.endian = Endian.LITTLE_ENDIAN;
  360.                      this.source.readBytes(this._currentLFH,0,4);
  361.                      magic = this._currentLFH.readUnsignedInt();
  362.                      if(ZIP_CDH_MAGIC != magic)
  363.                      {
  364.                         this.m_ucfParseState = AT_END;
  365.                         return;
  366.                      }
  367.                      this.m_ucfParseState = AT_CDHEADERMAGIC;
  368.                   case AT_CDHEADERMAGIC:
  369.                      if(this.source.bytesAvailable < CDHEADER_SIZE_BYTES - 4)
  370.                      {
  371.                         return;
  372.                      }
  373.                      this.source.readBytes(this._currentLFH,this._currentLFH.length,CDHEADER_SIZE_BYTES - 4);
  374.                      this._currentLFH.position += 24;
  375.                      this._filenameLength = this._currentLFH.readUnsignedShort();
  376.                      this._extraFieldLength = this._currentLFH.readUnsignedShort();
  377.                      this._fileCommentLength = this._currentLFH.readUnsignedShort();
  378.                      this._currentLFH.position += 8;
  379.                      this._fileRelativeOffset = this._currentLFH.readUnsignedInt();
  380.                      this.m_ucfParseState = AT_CDFILENAME;
  381.                   case AT_CDFILENAME:
  382.                      if(this.source.bytesAvailable < this._filenameLength)
  383.                      {
  384.                         return;
  385.                      }
  386.                      this.source.readBytes(this._currentLFH,this._currentLFH.length,this._filenameLength);
  387.                      filename = new ByteArray();
  388.                      this._currentLFH.readBytes(filename,0,this._filenameLength);
  389.                      this._path = filename.toString();
  390.                      this.m_ucfParseState = AT_CDEXTRA_FIELD;
  391.                   case AT_CDEXTRA_FIELD:
  392.                      if(this.source.bytesAvailable < this._extraFieldLength)
  393.                      {
  394.                         return;
  395.                      }
  396.                      if(this._extraFieldLength > 0)
  397.                      {
  398.                         this.source.readBytes(this._currentLFH,this._currentLFH.length,this._extraFieldLength);
  399.                      }
  400.                      this.m_ucfParseState = AT_CDCOMMENT;
  401.                   case AT_CDCOMMENT:
  402.                      if(this.source.bytesAvailable < this._fileCommentLength)
  403.                      {
  404.                         return;
  405.                      }
  406.                      if(this._fileCommentLength > 0)
  407.                      {
  408.                         this.source.readBytes(this._currentLFH,this._currentLFH.length,this._fileCommentLength);
  409.                      }
  410.                      break;
  411.                   case AT_END:
  412.                      return;
  413.                   case AT_ABORTED:
  414.                      return;
  415.                   case AT_ERROR:
  416.                      return;
  417.                }
  418.                this.m_ucfParseState = AT_CDHEADER;
  419.             }
  420.             return;
  421.          }
  422.          catch(e:Error)
  423.          {
  424.             dispatchError(e);
  425.          }
  426.       }
  427.       
  428.       private function dispatchError(param1:Error) : void
  429.       {
  430.          this.m_ucfParseState = AT_ERROR;
  431.          dispatchEvent(new ErrorEvent(ErrorEvent.ERROR,false,false,param1.message,param1.errorID));
  432.       }
  433.       
  434.       private function onComplete(param1:Event) : void
  435.       {
  436.          var event:Event = param1;
  437.          try
  438.          {
  439.             switch(this.m_ucfParseState)
  440.             {
  441.                case AT_END:
  442.                   this.onDone();
  443.                   this.m_ucfParseState = AT_COMPLETE;
  444.                   if(this.m_enableSignatureValidation && this.m_validator.packageSignatureStatus != 0)
  445.                   {
  446.                      dispatchEvent(new ErrorEvent(ErrorEvent.ERROR,false,false,"signature is not valid"));
  447.                      transition(this.errored);
  448.                   }
  449.                   else
  450.                   {
  451.                      transition(this.complete);
  452.                   }
  453.                   break;
  454.                case AT_ABORTED:
  455.                   this.m_isComplete = true;
  456.                   dispatchEvent(new Event(Event.COMPLETE));
  457.                   break;
  458.                case AT_ERROR:
  459.                   break;
  460.                default:
  461.                   throw new Error("truncated or corrupt",Constants.ERROR_UCF_CORRUPT_AIR);
  462.             }
  463.          }
  464.          catch(e:Error)
  465.          {
  466.             dispatchError(e);
  467.          }
  468.       }
  469.       
  470.       private function complete(param1:Event) : void
  471.       {
  472.          switch(param1.type)
  473.          {
  474.             case HSMEvent.ENTER:
  475.                this.m_isComplete = true;
  476.                dispatchEvent(new Event(Event.COMPLETE));
  477.          }
  478.       }
  479.       
  480.       protected function onDirectory(param1:String) : void
  481.       {
  482.       }
  483.       
  484.       private function initialized(param1:Event) : void
  485.       {
  486.       }
  487.       
  488.       protected function get ucfParseState() : uint
  489.       {
  490.          return this.m_ucfParseState;
  491.       }
  492.       
  493.       public function set outputDirectory(param1:File) : void
  494.       {
  495.          this.m_dir = param1;
  496.       }
  497.       
  498.       public function get outputDirectory() : File
  499.       {
  500.          return this.m_dir;
  501.       }
  502.       
  503.       public function unpackageAsync(param1:String) : void
  504.       {
  505.          this.identifier = param1;
  506.          transitionAsync(this.unpackaging);
  507.       }
  508.       
  509.       public function cancel() : void
  510.       {
  511.          if(Boolean(this.source) && this.source.connected)
  512.          {
  513.             this.source.close();
  514.             this.m_ucfParseState = AT_ABORTED;
  515.          }
  516.       }
  517.       
  518.       protected function onFile(param1:uint, param2:String, param3:ByteArray) : Boolean
  519.       {
  520.          return true;
  521.       }
  522.    }
  523. }
  524.  
  525.