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