001package ezvcard.io.scribe;
002
003import ezvcard.io.CannotParseException;
004import ezvcard.io.ParseContext;
005import ezvcard.io.html.HCardElement;
006import ezvcard.parameter.SoundType;
007import ezvcard.property.Sound;
008import ezvcard.util.DataUri;
009
010/*
011 Copyright (c) 2012-2023, Michael Angstadt
012 All rights reserved.
013
014 Redistribution and use in source and binary forms, with or without
015 modification, are permitted provided that the following conditions are met: 
016
017 1. Redistributions of source code must retain the above copyright notice, this
018 list of conditions and the following disclaimer. 
019 2. Redistributions in binary form must reproduce the above copyright notice,
020 this list of conditions and the following disclaimer in the documentation
021 and/or other materials provided with the distribution. 
022
023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
024 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
025 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
026 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
027 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
028 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
029 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
030 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
031 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
032 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
033 */
034
035/**
036 * Marshals {@link Sound} properties.
037 * @author Michael Angstadt
038 */
039public class SoundScribe extends BinaryPropertyScribe<Sound, SoundType> {
040        public SoundScribe() {
041                super(Sound.class, "SOUND");
042        }
043
044        @Override
045        protected SoundType _mediaTypeFromTypeParameter(String type) {
046                return SoundType.get(type, null, null);
047        }
048
049        @Override
050        protected SoundType _mediaTypeFromMediaTypeParameter(String mediaType) {
051                return SoundType.get(null, mediaType, null);
052        }
053
054        @Override
055        protected SoundType _mediaTypeFromFileExtension(String extension) {
056                return SoundType.find(null, null, extension);
057        }
058
059        @Override
060        protected Sound _newInstance(String uri, SoundType contentType) {
061                return new Sound(uri, contentType);
062        }
063
064        @Override
065        protected Sound _newInstance(byte[] data, SoundType contentType) {
066                return new Sound(data, contentType);
067        }
068
069        @Override
070        protected Sound _parseHtml(HCardElement element, ParseContext context) {
071                String elementName = element.tagName();
072                if (!"audio".equals(elementName) && !"source".equals(elementName)) {
073                        return super._parseHtml(element, context);
074                }
075
076                if ("audio".equals(elementName)) {
077                        //parse its child "<source>" element
078                        org.jsoup.nodes.Element source = element.getElement().getElementsByTag("source").first();
079                        if (source == null) {
080                                throw new CannotParseException(16);
081                        }
082
083                        element = new HCardElement(source);
084                }
085
086                String src = element.absUrl("src");
087                if (src.isEmpty()) {
088                        throw new CannotParseException(17);
089                }
090
091                String type = element.attr("type");
092                SoundType mediaType = type.isEmpty() ? null : _mediaTypeFromMediaTypeParameter(type);
093
094                try {
095                        DataUri uri = DataUri.parse(src);
096                        mediaType = _mediaTypeFromMediaTypeParameter(uri.getContentType());
097                        return new Sound(uri.getData(), mediaType);
098                } catch (IllegalArgumentException e) {
099                        //not a data URI
100                        if (mediaType == null) {
101                                String extension = getFileExtension(src);
102                                mediaType = (extension == null) ? null : _mediaTypeFromFileExtension(extension);
103                        }
104                        return new Sound(src, mediaType);
105                }
106        }
107}