001/**
002 *
003 * Copyright © 2017 Paul Schaub, 2019 Florian Schmaus
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.jivesoftware.smackx.jingle_filetransfer.element;
018
019import org.jivesoftware.smack.packet.XmlElement;
020import org.jivesoftware.smack.util.XmlStringBuilder;
021
022import org.jivesoftware.smackx.hashes.element.HashElement;
023
024/**
025 * RangeElement which specifies, which range of a file shall be transferred.
026 */
027public class Range implements XmlElement {
028
029    public static final String ELEMENT = "range";
030    public static final String NAMESPACE = JingleFileTransferChild.NAMESPACE;
031
032    public static final String ATTR_OFFSET = "offset";
033    public static final String ATTR_LENGTH = "length";
034
035    private final Integer offset, length;
036    private final HashElement hash;
037
038    /**
039     * Create a Range element with default values.
040     */
041    public Range() {
042        this(null, null, null);
043    }
044
045    /**
046     * Create a Range element with specified length.
047     * @param length length of the transmitted data in bytes.
048     */
049    public Range(int length) {
050        this(null, length, null);
051    }
052
053    /**
054     * Create a Range element with specified offset and length.
055     * @param offset offset in bytes from the beginning of the transmitted data.
056     * @param length number of bytes that shall be transferred.
057     */
058    public Range(int offset, int length) {
059        this(offset, length, null);
060    }
061
062    /**
063     * Create a Range element with specified offset, length and hash.
064     * @param offset offset in bytes from the beginning of the transmitted data.
065     * @param length number of bytes that shall be transferred.
066     * @param hash hash of the bytes in the specified range.
067     */
068    public Range(Integer offset, Integer length, HashElement hash) {
069        this.offset = offset;
070        this.length = length;
071        this.hash = hash;
072    }
073
074    /**
075     * Return the index of the offset.
076     * This marks the begin of the specified range.
077     * @return offset TODO javadoc me please
078     */
079    public int getOffset() {
080        return offset;
081    }
082
083    /**
084     * Return the length of the range.
085     * @return length TODO javadoc me please
086     */
087    public int getLength() {
088        return length;
089    }
090
091    /**
092     * Return the hash element that contains a checksum of the bytes specified in the range.
093     * @return hash element
094     */
095    public HashElement getHash() {
096        return hash;
097    }
098
099    @Override
100    public String getElementName() {
101        return ELEMENT;
102    }
103
104    @Override
105    public String getNamespace() {
106        return NAMESPACE;
107    }
108
109    @Override
110    public CharSequence toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) {
111        XmlStringBuilder sb =  new XmlStringBuilder(this);
112
113        sb.optAttribute(ATTR_OFFSET, offset);
114        sb.optAttribute(ATTR_LENGTH, length);
115
116        if (hash != null) {
117            sb.rightAngleBracket();
118            sb.append(hash);
119            sb.closeElement(this);
120        } else {
121            sb.closeEmptyElement();
122        }
123        return sb;
124    }
125
126    @Override
127    public boolean equals(Object other) {
128        if (other == null || !(other instanceof Range)) {
129            return false;
130        }
131
132        Range otherRange = (Range) other;
133        return this.getOffset() == otherRange.getOffset() &&
134            this.getLength() == otherRange.getLength() &&
135            this.getHash().equals(otherRange.getHash());
136    }
137
138    @Override
139    public int hashCode() {
140        return toXML().toString().hashCode();
141    }
142}