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-2018, 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                return super._dataType(property, version);
061        }
062
063        @Override
064        protected void _prepareParameters(Key property, VCardParameters copy, VCardVersion version, VCard vcard) {
065                if (property.getText() != null) {
066                        MediaTypeParameter contentType = property.getContentType();
067                        if (contentType == null) {
068                                contentType = new MediaTypeParameter(null, null, null);
069                        }
070
071                        copy.setEncoding(null);
072
073                        switch (version) {
074                        case V2_1:
075                                copy.setType(contentType.getValue());
076                                copy.setMediaType(null);
077                                break;
078                        case V3_0:
079                                copy.setType(contentType.getValue());
080                                copy.setMediaType(null);
081                                break;
082                        case V4_0:
083                                copy.setMediaType(contentType.getMediaType());
084                                break;
085                        }
086
087                        return;
088                }
089
090                super._prepareParameters(property, copy, version, vcard);
091        }
092
093        @Override
094        protected String _writeText(Key property, WriteContext context) {
095                String text = property.getText();
096                if (text != null) {
097                        return text;
098                }
099
100                return super._writeText(property, context);
101        }
102
103        @Override
104        protected Key _parseText(String value, VCardDataType dataType, VCardParameters parameters, ParseContext context) {
105                value = VObjectPropertyValues.unescape(value);
106
107                /*
108                 * Parse as text if VALUE parameter is explicitly set to TEXT.
109                 */
110                if (dataType == VCardDataType.TEXT) {
111                        KeyType contentType = parseContentTypeFromValueAndParameters(value, parameters, context.getVersion());
112                        Key property = new Key();
113                        property.setText(value, contentType);
114                        return property;
115                }
116
117                return parse(value, dataType, parameters, context.getVersion());
118        }
119
120        @Override
121        protected void _writeXml(Key property, XCardElement parent) {
122                String text = property.getText();
123                if (text != null) {
124                        parent.append(VCardDataType.TEXT, text);
125                        return;
126                }
127
128                super._writeXml(property, parent);
129        }
130
131        @Override
132        protected Key _parseXml(XCardElement element, VCardParameters parameters, ParseContext context) {
133                String text = element.first(VCardDataType.TEXT);
134                if (text != null) {
135                        KeyType contentType = parseContentTypeFromValueAndParameters(text, parameters, element.version());
136                        Key property = new Key();
137                        property.setText(text, contentType);
138                        return property;
139                }
140
141                String value = element.first(VCardDataType.URI);
142                if (value != null) {
143                        return parse(value, VCardDataType.URI, parameters, element.version());
144                }
145
146                throw missingXmlElements(VCardDataType.URI, VCardDataType.TEXT);
147        }
148
149        @Override
150        protected JCardValue _writeJson(Key property) {
151                String text = property.getText();
152                if (text != null) {
153                        return JCardValue.single(text);
154                }
155
156                return super._writeJson(property);
157        }
158
159        @Override
160        protected Key _parseJson(JCardValue value, VCardDataType dataType, VCardParameters parameters, ParseContext context) {
161                if (dataType == VCardDataType.TEXT) {
162                        String valueStr = value.asSingle();
163                        KeyType contentType = parseContentTypeFromValueAndParameters(valueStr, parameters, VCardVersion.V4_0);
164                        Key property = new Key();
165                        property.setText(valueStr, contentType);
166                        return property;
167                }
168
169                return super._parseJson(value, dataType, parameters, context);
170        }
171
172        @Override
173        protected KeyType _mediaTypeFromTypeParameter(String type) {
174                return KeyType.get(type, null, null);
175        }
176
177        @Override
178        protected KeyType _mediaTypeFromMediaTypeParameter(String mediaType) {
179                return KeyType.get(null, mediaType, null);
180        }
181
182        @Override
183        protected KeyType _mediaTypeFromFileExtension(String extension) {
184                return KeyType.find(null, null, extension);
185        }
186
187        @Override
188        protected Key _newInstance(String uri, KeyType contentType) {
189                return new Key(uri, contentType);
190        }
191
192        @Override
193        protected Key _newInstance(byte[] data, KeyType contentType) {
194                return new Key(data, contentType);
195        }
196
197        @Override
198        protected Key cannotUnmarshalValue(String value, VCardVersion version, KeyType contentType) {
199                switch (version) {
200                case V2_1:
201                case V3_0:
202                        /*
203                         * It wasn't explicitly defined as a URI, and didn't have an
204                         * ENCODING parameter, so treat it as text.
205                         */
206                        Key key = new Key();
207                        key.setText(value, contentType);
208                        return key;
209                case V4_0:
210                        /*
211                         * It wasn't explicitly defined as a text value, and it could not be
212                         * parsed as a data URI, so treat it as a generic URI.
213                         */
214                        return new Key(value, contentType);
215                }
216
217                return null;
218        }
219}