001package ezvcard.property;
002
003import java.io.BufferedInputStream;
004import java.io.IOException;
005import java.io.InputStream;
006import java.nio.file.Files;
007import java.nio.file.Path;
008import java.util.Arrays;
009import java.util.LinkedHashMap;
010import java.util.List;
011import java.util.Map;
012import java.util.Objects;
013
014import ezvcard.VCard;
015import ezvcard.VCardVersion;
016import ezvcard.ValidationWarning;
017import ezvcard.parameter.MediaTypeParameter;
018import ezvcard.parameter.Pid;
019import ezvcard.util.Gobble;
020
021/*
022 Copyright (c) 2012-2026, Michael Angstadt
023 All rights reserved.
024
025 Redistribution and use in source and binary forms, with or without
026 modification, are permitted provided that the following conditions are met: 
027
028 1. Redistributions of source code must retain the above copyright notice, this
029 list of conditions and the following disclaimer. 
030 2. Redistributions in binary form must reproduce the above copyright notice,
031 this list of conditions and the following disclaimer in the documentation
032 and/or other materials provided with the distribution. 
033
034 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
035 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
036 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
037 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
038 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
039 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
040 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
041 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
042 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
043 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
044
045 The views and conclusions contained in the software and documentation are those
046 of the authors and should not be interpreted as representing official policies, 
047 either expressed or implied, of the FreeBSD Project.
048 */
049
050/**
051 * Represents a property whose value contains binary data.
052 * @author Michael Angstadt
053 * @param <T> the class used for representing the content type of the resource
054 */
055public abstract class BinaryProperty<T extends MediaTypeParameter> extends VCardProperty implements HasAltId {
056        /**
057         * The decoded data.
058         */
059        protected byte[] data;
060
061        /**
062         * The URL to the resource.
063         */
064        protected String url;
065
066        /**
067         * The content type of the resource (for example, a JPEG image).
068         */
069        protected T contentType;
070
071        protected BinaryProperty() {
072                //empty
073        }
074
075        /**
076         * Creates a binary property.
077         * @param url the URL to the resource
078         * @param type the content type
079         */
080        protected BinaryProperty(String url, T type) {
081                setUrl(url, type);
082        }
083
084        /**
085         * Creates a binary property.
086         * @param data the binary data
087         * @param type the content type
088         */
089        protected BinaryProperty(byte[] data, T type) {
090                setData(data, type);
091        }
092
093        /**
094         * Creates a binary property.
095         * @param in an input stream to the binary data (will be closed)
096         * @param type the content type
097         * @throws IOException if there is a problem reading from the input stream
098         */
099        protected BinaryProperty(InputStream in, T type) throws IOException {
100                this(new Gobble(in).asByteArray(), type);
101        }
102
103        /**
104         * Creates a binary property.
105         * @param file the file containing the binary data
106         * @param type the content type
107         * @throws IOException if there is a problem reading from the file
108         */
109        protected BinaryProperty(Path file, T type) throws IOException {
110                this(new BufferedInputStream(Files.newInputStream(file)), type);
111        }
112
113        /**
114         * Copy constructor.
115         * @param original the property to make a copy of
116         */
117        protected BinaryProperty(BinaryProperty<T> original) {
118                super(original);
119                data = (original.data == null) ? null : original.data.clone();
120                url = original.url;
121                contentType = original.contentType;
122        }
123
124        /**
125         * Gets the binary data of the resource.
126         * @return the binary data or null if there is none
127         */
128        public byte[] getData() {
129                return data;
130        }
131
132        /**
133         * Sets the binary data of the resource.
134         * @param data the binary data
135         * @param type the content type (e.g. "JPEG image")
136         */
137        public void setData(byte[] data, T type) {
138                this.url = null;
139                this.data = data;
140                setContentType(type);
141        }
142
143        /**
144         * Gets the URL to the resource
145         * @return the URL or null if there is none
146         */
147        public String getUrl() {
148                return url;
149        }
150
151        /**
152         * Sets the URL to the resource.
153         * @param url the URL
154         * @param type the content type (e.g. "JPEG image")
155         */
156        public void setUrl(String url, T type) {
157                this.url = url;
158                this.data = null;
159                setContentType(type);
160        }
161
162        /**
163         * Gets the content type of the resource.
164         * @return the content type (e.g. "JPEG image")
165         */
166        public T getContentType() {
167                return contentType;
168        }
169
170        /**
171         * Sets the content type of the resource.
172         * @param contentType the content type (e.g. "JPEG image")
173         */
174        public void setContentType(T contentType) {
175                this.contentType = contentType;
176        }
177
178        /**
179         * Gets the vCard 4.0 TYPE parameter. This should NOT be used to get the
180         * TYPE parameter for 2.1/3.0 vCards. Use {@link #getContentType} instead.
181         * <p>
182         * <b>Supported versions:</b> {@code 4.0}
183         * </p>
184         * @return the TYPE value (typically, this will be either "work" or "home")
185         * or null if it doesn't exist
186         */
187        public String getType() {
188                return parameters.getType();
189        }
190
191        /**
192         * Sets the vCard 4.0 TYPE parameter. This should NOT be used to set the
193         * TYPE parameter for 2.1/3.0 vCards. Use {@link #setContentType} instead.
194         * <p>
195         * <b>Supported versions:</b> {@code 4.0}
196         * </p>
197         * @param type the TYPE value (should be either "work" or "home") or null to
198         * remove
199         */
200        public void setType(String type) {
201                parameters.setType(type);
202        }
203
204        @Override
205        public List<Pid> getPids() {
206                return super.getPids();
207        }
208
209        @Override
210        public Integer getPref() {
211                return super.getPref();
212        }
213
214        @Override
215        public void setPref(Integer pref) {
216                super.setPref(pref);
217        }
218
219        //@Override
220        public String getAltId() {
221                return parameters.getAltId();
222        }
223
224        //@Override
225        public void setAltId(String altId) {
226                parameters.setAltId(altId);
227        }
228
229        @Override
230        protected void _validate(List<ValidationWarning> warnings, VCardVersion version, VCard vcard) {
231                if (url == null && data == null) {
232                        warnings.add(new ValidationWarning(8));
233                }
234        }
235
236        @Override
237        protected Map<String, Object> toStringValues() {
238                Map<String, Object> values = new LinkedHashMap<>();
239                values.put("data", (data == null) ? "null" : "length: " + data.length);
240                values.put("url", url);
241                values.put("contentType", contentType);
242                return values;
243        }
244
245        @Override
246        public int hashCode() {
247                final int prime = 31;
248                int result = super.hashCode();
249                result = prime * result + Arrays.hashCode(data);
250                result = prime * result + Objects.hash(contentType, url);
251                return result;
252        }
253
254        @Override
255        public boolean equals(Object obj) {
256                if (this == obj) return true;
257                if (!super.equals(obj)) return false;
258                if (getClass() != obj.getClass()) return false;
259                BinaryProperty<?> other = (BinaryProperty<?>) obj;
260                return Objects.equals(contentType, other.contentType) && Arrays.equals(data, other.data) && Objects.equals(url, other.url);
261        }
262}