Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /* ************************************************************************
  #
  #  DivConq
  #
  #  http://divconq.com/
  #
  #  Copyright:
  #    Copyright 2014 eTimeline, LLC. All rights reserved.
  #
 #  License:
 #    See the license.txt file in the project's top-level directory for details.
 #
 #  Authors:
 #    * Andy White
 #
 ************************************************************************ */
 package divconq.io.stream;
 
 
 import java.util.List;
 
 
 
 public class UngzipStream extends BaseStream implements IStreamSource {
 	protected static final int FHCRC = 0x02;
     protected static final int FEXTRA = 0x04;
     protected static final int FNAME = 0x08;
     protected static final int FCOMMENT = 0x10;
     protected static final int FRESERVED = 0xE0;
 
     private enum GzipState {
         HEADER_START,
         FLG_READ,
         XLEN_READ,
         SKIP_FNAME,
         SKIP_COMMENT,
         PROCESS_FHCRC,
         PRROCESS_CONTENT,
         PROCESS_FOOTER,
         DONE
     }
 
     protected GzipState gzipState = .;
     protected int flags = -1;
     protected int xlen = -1;
 
 	protected Inflater inflater = null;
 	protected byte[] dictionary = null;
     protected CRC32 crc = new CRC32();
     
     protected List<ByteBufoutlist = new ArrayList<>();
     
     protected String nameHint = null;
     protected String ourpath = null;
     protected long ourmod = 0;
     protected byte ourperm = 0;
     protected boolean eofsent = false;
     
     protected ByteBuf remnant = null;
 
     public UngzipStream() {
         this. = new Inflater(true);
         this. = new CRC32();
     }
 
     public UngzipStream(byte[] dictionary) {
     	this();
         this. = dictionary;
     }
     
 	public void init(StackEntry stackXElement el) {
 		this. = stack.stringFromElement(el"NameHint");
 	}
     
     public void close() {
 		Inflater inf = this.;
 		
 		if (inf != null)
 			inf.end();
 		
     	this. = null;
     	
 		ByteBuf rem = this.;
		if (rem != null) {
			rem.release();
			this. = null;
		}
    	
    	// not truly thread safe, consider
    	for (ByteBuf bb : this.)
    		bb.release();
    	
    	this..clear();
    
    	super.close();
    }
	// make sure we don't return without first releasing the file reference content
    @Override
    public HandleReturn handle(TaskRun cbStreamMessage msg) {
    	if (msg == .
    		return this..handle(cbmsg);
    	
    	if (this. == null)
    		this.initializeFileValues(msg);
    	
    	// inflate the payload into 1 or more outgoing buffers set in a queue
    	ByteBuf in = msg.getPayload();
    	
		if (in != null) {
			ByteBuf rem = this.;
			ByteBuf src = ((rem != null) && rem.isReadable()) 
					? Unpooled.wrappedBuffer(remin)
in;
			this.inflate(cbsrc);
			// if there are any unread bytes here we need to store them and combine with the next "handle"
			// this would be rare since the header and footer are small, but it is possible and should be handled
			// file content has its own "in progress" buffer so no need to worry about that
			this. = src.isReadable() ? src.copy() : null;
	        if (in != null)
	        	in.release();
	        
			if (rem != null
				rem.release();
			if(cb.isKilled())
		}
		// write all buffers in the queue
		while (this..size() > 0) {
			HandleReturn ret = this..handle(cbthis.nextMessage());
			if (ret != .)
				return ret;
		}
		// if we reached done and we wrote all the buffers, then send the EOF marker if not already
		if ((this. == .) && !this.)
			return this..handle(cbthis.nextMessage());
		// otherwise we need more data
    }
    
    // TODO return null if not EOF and if no bytes to send - there is no point in sending messages
    // downstream without content or EOF
    public StreamMessage nextMessage() {
		// create the output message
		blk.setPath(this.);
		if (this..size() > 0) {
			ByteBuf out = this..remove(0);
			// TODO blk.setPayloadoffset(v);		
			blk.setPayload(out);
		}
		boolean eof = (this..size() == 0) && (this. == .);
       	blk.setEof(eof);
       	
       	// set it on but never off
       	if (eof)
       		this. = true;
        
        return blk;
    }
    
    public void initializeFileValues(StreamMessage src) {
		if (StringUtil.isNotEmpty(this.)) 
			this. = "/" +  this.;
		else if (src.getPath() != null
			this. = "/" +  GzipUtils.getUncompressedFilename(src.getPath().getFileName());
		else
			this. = "/" + FileUtil.randomFilename("bin");    	
		this. = src.getModified();
		this. = src.getPermission();
    }
    // return true when completely done
    protected void inflate(TaskRun cbByteBuf in) {
        switch (this.) {
        case :
            if (in.readableBytes() < 10) 
                return;
            
            // read magic numbers
            int magic0 = in.readByte();
            int magic1 = in.readByte();
            if (magic0 != 31) {
                cb.kill("Input is not in the GZIP format");
                return;
            }
            
            this..update(magic0);
            this..update(magic1);
            int method = in.readUnsignedByte();
            
            if (method != .) {
            	cb.kill("Unsupported compression method " + method + " in the GZIP header");
            	return;
            }
            
            this..update(method);
            this. = in.readUnsignedByte();
            this..update(this.);
            if ((this. & ) != 0) {
            	cb.kill("Reserved flags are set in the GZIP header");
                return;
            }
            
            // mtime (int)
            this..update(in.readByte());
            this..update(in.readByte());
            this..update(in.readByte());
            this..update(in.readByte());
            this..update(in.readUnsignedByte()); // extra flags
            this..update(in.readUnsignedByte()); // operating system
            this. = .;
        case :
            if ((this. & ) != 0) {
                if (in.readableBytes() < 2) 
                    return;
                
                int xlen1 = in.readUnsignedByte();
                int xlen2 = in.readUnsignedByte();
                
                this..update(xlen1);
                this..update(xlen2);
                this. |= xlen1 << 8 | xlen2;
            }
            
            this. = .;
        case :
            if (this. != -1) {
                if (in.readableBytes() < 
                    return;
                
                byte[] xtra = new byte[];
                in.readBytes(xtra);
                this..update(xtra);
            }
            
            this. = .;
        case :
            if ((this. & ) != 0) {
                boolean gotend = false;
                
                while (in.isReadable()) {
                    int b = in.readUnsignedByte();
                    this..update(b);
                    
                    if (b == 0x00) {
                    	gotend = true;
                        break;
                    }
                } 
                
                if (!gotend)
                	return;
            }
            
            this. = .;
        case :
            if ((this. & ) != 0) {
                boolean gotend = false;
                
                while (in.isReadable()) {
                    int b = in.readUnsignedByte();
                    this..update(b);
                    
                    if (b == 0x00) {
                    	gotend = true;
                        break;
                    }
                } 
                
                if (!gotend)
                	return;
            }
            
            this. = .;
        case :
            if ((this. & ) != 0) {
                if (in.readableBytes() < 4) 
                    return;
                
                long crcValue = 0;
                
                for (int i = 0; i < 4; ++i
                    crcValue |= (longin.readUnsignedByte() << i * 8;
                long readCrc = .getValue();
                
                if (crcValue != readCrc) {
                	cb.kill("CRC value missmatch. Expected: " + crcValue + ", Got: " + readCrc);
                    return;
                }
            }
            
            this..reset();
            
            this. = .;
        case :
            int readableBytes = in.readableBytes();
            
            if (readableBytes < 1)
            	return;
            
            if (in.hasArray()) {
            	this..setInput(in.array(), in.arrayOffset() + in.readerIndex(), readableBytes);
            } 
            else {
                byte[] array = new byte[readableBytes];
                in.getBytes(in.readerIndex(), array);
                this..setInput(array);
            }
            int maxOutputLength = this..getRemaining() << 1;
            ByteBuf decompressed = ..getBufferAllocator().heapBuffer(maxOutputLength);
            
            boolean readFooter = false;
            byte[] outArray = decompressed.array();
            
            try {
                while (!this..needsInput()) {
                    int writerIndex = decompressed.writerIndex();
                    int outIndex = decompressed.arrayOffset() + writerIndex;
                    int length = decompressed.writableBytes();
                    if (length == 0) {
                        // completely filled the buffer allocate a new one and start to fill it
                    	this..add(decompressed);
                        decompressed = ..getBufferAllocator().heapBuffer(maxOutputLength);
                        outArray = decompressed.array();
                        continue;
                    }
                    int outputLength = this..inflate(outArrayoutIndexlength);
                    
                    if (outputLength > 0) {
                        decompressed.writerIndex(writerIndex + outputLength);
                        
                       	this..update(outArrayoutIndexoutputLength);
                    } 
                    else {
                        if (this..needsDictionary()) {
                            if (this. == null) {
                            	cb.kill("decompression failure, unable to set dictionary as non was specified");
                            	return;
                            }
                            
                            this..setDictionary(this.);
                        }
                    }
                    if (this..finished()) {
                        readFooter = true;
                        break;
                    }
                }
                in.skipBytes(readableBytes - this..getRemaining());
            } 
            catch (DataFormatException x) {
            	cb.kill("decompression failure: " + x);
            	return;
            } 
            finally {
                if (decompressed.isReadable()) {
                    this..add(decompressed);
                } 
                else {
                    decompressed.release();
                }
            }
        	
            if (!readFooter
            	break;
            
        	this. = .;
        case :
            if (in.readableBytes() < 8) 
                return;
            long crcValue = 0;
            
            for (int i = 0; i < 4; ++i
                crcValue |= (longin.readUnsignedByte() << i * 8;
            
            long readCrc = this..getValue();
            
            if (crcValue != readCrc) {
            	cb.kill("CRC value missmatch. Expected: " + crcValue + ", Got: " + readCrc);
            	return;
            }
            // read ISIZE and verify
            int dataLength = 0;
            
            for (int i = 0; i < 4; ++i
                dataLength |= in.readUnsignedByte() << i * 8;
            
            int readLength = this..getTotalOut();
            
            if (dataLength != readLength) {
            	cb.kill("Number of bytes mismatch. Expected: " + dataLength + ", Got: " + readLength);
            	return;
            }
            
        	this. = .;
        case :
        	break;
        }
    }
    // TODO if there is more from us then handle that before going upstream 
    
    @Override
    public void request(TaskRun cb) {
		// write all buffers in the queue
		while (this..size() > 0) {
			HandleReturn ret = this..handle(cbthis.nextMessage());
			if (ret != .)
				return;
		}
		// if we reached done and we wrote all the buffers, then send the EOF marker if not already
		if ((this. == .) && !this.) {
			HandleReturn ret = this..handle(cbthis.nextMessage());
			if (ret != .)
				return;
		}
    	this..request(cb);
    }	
New to GrepCode? Check out our FAQ X