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}