001/*
002 * Syncany, www.syncany.org
003 * Copyright (C) 2011-2016 Philipp C. Heckel <philipp.heckel@gmail.com> 
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU General Public License as published by
007 * the Free Software Foundation, either version 3 of the License, or
008 * (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU General Public License for more details.
014 *
015 * You should have received a copy of the GNU General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018package org.syncany.chunk;
019
020import java.io.ByteArrayOutputStream;
021import java.io.File;
022import java.io.IOException;
023import java.io.InputStream;
024import java.io.OutputStream;
025import java.util.zip.ZipEntry;
026import java.util.zip.ZipException;
027import java.util.zip.ZipFile;
028import java.util.zip.ZipInputStream;
029import java.util.zip.ZipOutputStream;
030
031import org.syncany.database.MultiChunkEntry.MultiChunkId;
032import org.syncany.util.StringUtil;
033
034/**
035 *
036 * @author Philipp C. Heckel (philipp.heckel@gmail.com)
037 */
038public class ZipMultiChunk extends MultiChunk {
039    private ZipOutputStream zipOut;
040    private ZipInputStream zipIn;
041    private ZipFile zipFile;
042
043    public ZipMultiChunk(InputStream is) {
044        super(0);
045        this.zipIn = new ZipInputStream(is);
046    }
047    
048    public ZipMultiChunk(File file) throws ZipException, IOException {
049                super(0);
050                this.zipFile = new ZipFile(file);
051        }    
052    
053    public ZipMultiChunk(MultiChunkId id, int minSize, OutputStream os) throws IOException {
054        super(id, minSize);        
055        
056        this.zipOut = new ZipOutputStream(os);
057        this.zipOut.setLevel(ZipOutputStream.STORED); // No compression        
058    }                
059
060        @Override
061    public boolean isFull() {
062        return size >= minSize*1024; // minSize is in KB!
063    }
064
065    @Override
066    public void write(Chunk chunk) throws IOException {
067        size += chunk.getSize();
068       
069        ZipEntry entry = new ZipEntry(StringUtil.toHex(chunk.getChecksum()));
070        entry.setSize(chunk.getSize());
071
072        zipOut.putNextEntry(entry);
073        zipOut.write(chunk.getContent(), 0, chunk.getSize());
074        zipOut.closeEntry();
075    }    
076    
077    @Override
078    public InputStream getChunkInputStream(byte[] checksum) throws IOException {
079        ZipEntry chunkEntry = zipFile.getEntry(StringUtil.toHex(checksum));
080        InputStream chunkInputStream = zipFile.getInputStream(chunkEntry);
081        
082        return chunkInputStream;
083    }
084    
085    @Override
086    public Chunk read() throws IOException {
087        ZipEntry entry = zipIn.getNextEntry();
088
089        if (entry == null) {
090            return null;
091        }
092        
093        int read;
094        ByteArrayOutputStream contentByteArray = new ByteArrayOutputStream();
095        
096        while (-1 != (read = zipIn.read())) {
097                contentByteArray.write(read);
098        }       
099        
100        return new Chunk(StringUtil.fromHex(entry.getName()), contentByteArray.toByteArray(), contentByteArray.size(), null);
101    }
102   
103
104    @Override
105    public long getSize() {
106        return size;
107    }
108
109    @Override
110    public void close() throws IOException {
111        if (zipOut != null) {
112            zipOut.close();
113        }
114
115        if (zipIn != null) {
116            zipIn.close();
117        }
118
119        if (zipFile != null) {
120            zipFile.close();
121        }
122    }
123}
124