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.database;
019
020import java.util.ArrayList;
021import java.util.Collections;
022import java.util.List;
023
024import org.syncany.database.ChunkEntry.ChunkChecksum;
025
026/**
027 * A file content represents the content of a file. It contains a list of
028 * references to {@link ChunkEntry}s, and identifies a content by its checksum.
029 *
030 * <p>A file content is implicitly referenced by one or many {@link FileVersion}s
031 * through the checksum attribute. A file content always contains the full list of
032 * chunks it resembles. There are no deltas!
033 *
034 * <p>Unlike the chunk list in a {@link MultiChunkEntry}, the order of the chunks
035 * is very important, because a file can only be reconstructed if the order of
036 * its chunks are followed.
037 *
038 * @author Philipp C. Heckel (philipp.heckel@gmail.com)
039 */
040public class FileContent {
041        private FileChecksum checksum;
042        private long size;
043
044        private List<ChunkChecksum> chunkChecksums;
045
046        public FileContent() {
047                this.chunkChecksums = new ArrayList<ChunkChecksum>();
048        }
049
050        public void addChunk(ChunkChecksum chunk) {
051                chunkChecksums.add(chunk);
052        }
053
054        public FileChecksum getChecksum() {
055                return checksum;
056        }
057
058        public void setChecksum(FileChecksum checksum) {
059                this.checksum = checksum;
060        }
061
062        public long getSize() {
063                return size;
064        }
065
066        public void setSize(long contentSize) {
067                size = contentSize;
068        }
069
070        public List<ChunkChecksum> getChunks() {
071                return Collections.unmodifiableList(chunkChecksums);
072        }
073
074        @Override
075        public int hashCode() {
076                final int prime = 31;
077                int result = 1;
078                result = prime * result + ((checksum == null) ? 0 : checksum.hashCode());
079                result = prime * result + ((chunkChecksums == null) ? 0 : chunkChecksums.hashCode());
080                result = prime * result + (int) (size ^ (size >>> 32));
081                return result;
082        }
083
084        @Override
085        public boolean equals(Object obj) {
086                if (this == obj) {
087                        return true;
088                }
089                if (obj == null) {
090                        return false;
091                }
092                if (!(obj instanceof FileContent)) {
093                        return false;
094                }
095                FileContent other = (FileContent) obj;
096                if (checksum == null) {
097                        if (other.checksum != null) {
098                                return false;
099                        }
100                }
101                else if (!checksum.equals(other.checksum)) {
102                        return false;
103                }
104                if (chunkChecksums == null) {
105                        if (other.chunkChecksums != null) {
106                                return false;
107                        }
108                }
109                else if (!chunkChecksums.equals(other.chunkChecksums)) {
110                        return false;
111                }
112                if (size != other.size) {
113                        return false;
114                }
115                return true;
116        }
117
118        @Override
119        public String toString() {
120                return "FileContent [checksum=" + checksum + ", contentSize=" + size + ", chunks=" + chunkChecksums + "]";
121        }
122
123        public static class FileChecksum extends ObjectId {
124                public FileChecksum(byte[] array) {
125                        super(array);
126                }
127
128                public static FileChecksum parseFileChecksum(String s) {
129                        return new FileChecksum(ObjectId.parseObjectId(s));
130                }
131
132                public static boolean fileChecksumEquals(FileChecksum checksum1, FileChecksum checksum2) {
133                        if (checksum1 != null && checksum2 != null) {
134                                return checksum1.equals(checksum2);
135                        }
136                        else {
137                                return checksum1 == null && checksum2 == null;
138                        }
139                }
140        }
141}