001package biweekly.io.scribe.property;
002
003import biweekly.ICalDataType;
004import biweekly.ICalVersion;
005import biweekly.io.ParseContext;
006import biweekly.io.WriteContext;
007import biweekly.io.json.JCalValue;
008import biweekly.io.xml.XCalElement;
009import biweekly.parameter.Encoding;
010import biweekly.parameter.ICalParameters;
011import biweekly.property.Attachment;
012import biweekly.util.org.apache.commons.codec.binary.Base64;
013
014/*
015 Copyright (c) 2013-2015, Michael Angstadt
016 All rights reserved.
017
018 Redistribution and use in source and binary forms, with or without
019 modification, are permitted provided that the following conditions are met: 
020
021 1. Redistributions of source code must retain the above copyright notice, this
022 list of conditions and the following disclaimer. 
023 2. Redistributions in binary form must reproduce the above copyright notice,
024 this list of conditions and the following disclaimer in the documentation
025 and/or other materials provided with the distribution. 
026
027 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
028 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
029 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
030 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
031 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
032 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
033 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
034 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
035 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
036 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
037 */
038
039/**
040 * Marshals {@link Attachment} properties.
041 * @author Michael Angstadt
042 */
043public class AttachmentScribe extends ICalPropertyScribe<Attachment> {
044        public AttachmentScribe() {
045                super(Attachment.class, "ATTACH", ICalDataType.URI);
046        }
047
048        @Override
049        protected ICalParameters _prepareParameters(Attachment property, WriteContext context) {
050                ICalParameters copy = new ICalParameters(property.getParameters());
051
052                if (property.getUri() != null) {
053                        copy.setEncoding(null);
054                } else if (property.getData() != null) {
055                        copy.setEncoding(Encoding.BASE64);
056                }
057
058                return copy;
059        }
060
061        @Override
062        protected ICalDataType _dataType(Attachment property, ICalVersion version) {
063                if (property.getUri() != null) {
064                        return (version == ICalVersion.V1_0) ? ICalDataType.URL : ICalDataType.URI;
065                }
066                if (property.getData() != null) {
067                        return ICalDataType.BINARY;
068                }
069                if (property.getContentId() != null) {
070                        return (version == ICalVersion.V1_0) ? ICalDataType.CONTENT_ID : ICalDataType.URI;
071                }
072                return defaultDataType(version);
073        }
074
075        @Override
076        protected String _writeText(Attachment property, WriteContext context) {
077                String uri = property.getUri();
078                if (uri != null) {
079                        return uri;
080                }
081
082                byte data[] = property.getData();
083                if (data != null) {
084                        return Base64.encodeBase64String(data);
085                }
086
087                String contentId = property.getContentId();
088                if (contentId != null) {
089                        return (context.getVersion() == ICalVersion.V1_0) ? contentId : "CID:" + contentId;
090                }
091
092                return "";
093        }
094
095        @Override
096        protected Attachment _parseText(String value, ICalDataType dataType, ICalParameters parameters, ParseContext context) {
097                value = unescape(value);
098
099                if (dataType == ICalDataType.BINARY || parameters.getEncoding() == Encoding.BASE64) {
100                        return new Attachment(null, Base64.decodeBase64(value));
101                }
102                return new Attachment(null, value);
103        }
104
105        @Override
106        protected void _writeXml(Attachment property, XCalElement element, WriteContext context) {
107                String uri = property.getUri();
108                if (uri != null) {
109                        element.append(ICalDataType.URI, uri);
110                        return;
111                }
112
113                byte data[] = property.getData();
114                if (data != null) {
115                        element.append(ICalDataType.BINARY, Base64.encodeBase64String(data));
116                        return;
117                }
118
119                element.append(defaultDataType(context.getVersion()), "");
120        }
121
122        @Override
123        protected Attachment _parseXml(XCalElement element, ICalParameters parameters, ParseContext context) {
124                String uri = element.first(ICalDataType.URI);
125                if (uri != null) {
126                        return new Attachment(null, uri);
127                }
128
129                String base64Data = element.first(ICalDataType.BINARY);
130                if (base64Data != null) {
131                        return new Attachment(null, Base64.decodeBase64(base64Data)); //formatType will be set when the parameters are assigned to the property object
132                }
133
134                throw missingXmlElements(ICalDataType.URI, ICalDataType.BINARY);
135        }
136
137        @Override
138        protected JCalValue _writeJson(Attachment property, WriteContext context) {
139                String uri = property.getUri();
140                if (uri != null) {
141                        return JCalValue.single(uri);
142                }
143
144                byte data[] = property.getData();
145                if (data != null) {
146                        return JCalValue.single(Base64.encodeBase64String(data));
147                }
148
149                return JCalValue.single("");
150        }
151
152        @Override
153        protected Attachment _parseJson(JCalValue value, ICalDataType dataType, ICalParameters parameters, ParseContext context) {
154                String valueStr = value.asSingle();
155
156                if (dataType == ICalDataType.BINARY) {
157                        return new Attachment(null, Base64.decodeBase64(valueStr));
158                }
159                return new Attachment(null, valueStr);
160        }
161}