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}