001package ezvcard.io.scribe; 002 003import com.github.mangstadt.vinnie.io.VObjectPropertyValues; 004 005import ezvcard.VCard; 006import ezvcard.VCardDataType; 007import ezvcard.VCardVersion; 008import ezvcard.io.ParseContext; 009import ezvcard.io.json.JCardValue; 010import ezvcard.io.text.WriteContext; 011import ezvcard.io.xml.XCardElement; 012import ezvcard.parameter.KeyType; 013import ezvcard.parameter.MediaTypeParameter; 014import ezvcard.parameter.VCardParameters; 015import ezvcard.property.Key; 016 017/* 018 Copyright (c) 2012-2023, Michael Angstadt 019 All rights reserved. 020 021 Redistribution and use in source and binary forms, with or without 022 modification, are permitted provided that the following conditions are met: 023 024 1. Redistributions of source code must retain the above copyright notice, this 025 list of conditions and the following disclaimer. 026 2. Redistributions in binary form must reproduce the above copyright notice, 027 this list of conditions and the following disclaimer in the documentation 028 and/or other materials provided with the distribution. 029 030 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 031 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 032 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 033 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 034 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 035 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 036 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 037 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 038 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 039 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 040 */ 041 042/** 043 * Marshals {@link Key} properties. 044 * @author Michael Angstadt 045 */ 046public class KeyScribe extends BinaryPropertyScribe<Key, KeyType> { 047 public KeyScribe() { 048 super(Key.class, "KEY"); 049 } 050 051 @Override 052 protected VCardDataType _dataType(Key property, VCardVersion version) { 053 /* 054 * Only include a "VALUE=TEXT" parameter if it's a 4.0 vCard. 055 */ 056 if (version == VCardVersion.V4_0 && property.getText() != null) { 057 return VCardDataType.TEXT; 058 } 059 060 /* 061 * Always use the URI data type with URL/URIs for consistency (even 062 * though 2.1 technically only supports the "URL" data type). 063 */ 064 if (property.getUrl() != null) { 065 return VCardDataType.URI; 066 } 067 068 return super._dataType(property, version); 069 } 070 071 @Override 072 protected void _prepareParameters(Key property, VCardParameters copy, VCardVersion version, VCard vcard) { 073 if (property.getText() != null) { 074 MediaTypeParameter contentType = property.getContentType(); 075 if (contentType == null) { 076 contentType = new MediaTypeParameter(null, null, null); 077 } 078 079 copy.setEncoding(null); 080 081 switch (version) { 082 case V2_1: 083 copy.setType(contentType.getValue()); 084 copy.setMediaType(null); 085 break; 086 case V3_0: 087 copy.setType(contentType.getValue()); 088 copy.setMediaType(null); 089 break; 090 case V4_0: 091 copy.setMediaType(contentType.getMediaType()); 092 break; 093 } 094 095 return; 096 } 097 098 super._prepareParameters(property, copy, version, vcard); 099 } 100 101 @Override 102 protected String _writeText(Key property, WriteContext context) { 103 String text = property.getText(); 104 if (text != null) { 105 return text; 106 } 107 108 return super._writeText(property, context); 109 } 110 111 @Override 112 protected Key _parseText(String value, VCardDataType dataType, VCardParameters parameters, ParseContext context) { 113 value = VObjectPropertyValues.unescape(value); 114 115 /* 116 * Parse as text if VALUE parameter is explicitly set to TEXT. 117 */ 118 if (dataType == VCardDataType.TEXT) { 119 KeyType contentType = parseContentTypeFromValueAndParameters(value, parameters, context.getVersion()); 120 Key property = new Key(); 121 property.setText(value, contentType); 122 return property; 123 } 124 125 return parse(value, dataType, parameters, context.getVersion()); 126 } 127 128 @Override 129 protected void _writeXml(Key property, XCardElement parent) { 130 String text = property.getText(); 131 if (text != null) { 132 parent.append(VCardDataType.TEXT, text); 133 return; 134 } 135 136 super._writeXml(property, parent); 137 } 138 139 @Override 140 protected Key _parseXml(XCardElement element, VCardParameters parameters, ParseContext context) { 141 String text = element.first(VCardDataType.TEXT); 142 if (text != null) { 143 KeyType contentType = parseContentTypeFromValueAndParameters(text, parameters, element.version()); 144 Key property = new Key(); 145 property.setText(text, contentType); 146 return property; 147 } 148 149 String value = element.first(VCardDataType.URI); 150 if (value != null) { 151 return parse(value, VCardDataType.URI, parameters, element.version()); 152 } 153 154 throw missingXmlElements(VCardDataType.URI, VCardDataType.TEXT); 155 } 156 157 @Override 158 protected JCardValue _writeJson(Key property) { 159 String text = property.getText(); 160 if (text != null) { 161 return JCardValue.single(text); 162 } 163 164 return super._writeJson(property); 165 } 166 167 @Override 168 protected Key _parseJson(JCardValue value, VCardDataType dataType, VCardParameters parameters, ParseContext context) { 169 if (dataType == VCardDataType.TEXT) { 170 String valueStr = value.asSingle(); 171 KeyType contentType = parseContentTypeFromValueAndParameters(valueStr, parameters, VCardVersion.V4_0); 172 Key property = new Key(); 173 property.setText(valueStr, contentType); 174 return property; 175 } 176 177 return super._parseJson(value, dataType, parameters, context); 178 } 179 180 @Override 181 protected KeyType _mediaTypeFromTypeParameter(String type) { 182 return KeyType.get(type, null, null); 183 } 184 185 @Override 186 protected KeyType _mediaTypeFromMediaTypeParameter(String mediaType) { 187 return KeyType.get(null, mediaType, null); 188 } 189 190 @Override 191 protected KeyType _mediaTypeFromFileExtension(String extension) { 192 return KeyType.find(null, null, extension); 193 } 194 195 @Override 196 protected Key _newInstance(String uri, KeyType contentType) { 197 return new Key(uri, contentType); 198 } 199 200 @Override 201 protected Key _newInstance(byte[] data, KeyType contentType) { 202 return new Key(data, contentType); 203 } 204 205 @Override 206 protected Key cannotUnmarshalValue(String value, VCardVersion version, KeyType contentType) { 207 switch (version) { 208 case V2_1: 209 case V3_0: 210 /* 211 * It wasn't explicitly defined as a URI, and didn't have an 212 * ENCODING parameter, so treat it as text. 213 */ 214 Key key = new Key(); 215 key.setText(value, contentType); 216 return key; 217 case V4_0: 218 /* 219 * It wasn't explicitly defined as a text value, and it could not be 220 * parsed as a data URI, so treat it as a generic URI. 221 */ 222 return new Key(value, contentType); 223 } 224 225 return null; 226 } 227}