/*
* ====================================================================
* Copyright (c) 2004-2012 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core;
import java.io.UnsupportedEncodingException;
import java.io.Serializable;
import java.util.Arrays;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
/**
* The <b>SVNPropertyValue</b> represents an object wrapper for string and binary version controlled
* properties providing a set of specific methods to work with them.
*
* <p/>
* Since version 1.2 the <code>SVNKit</code> library supports binary properties as well.
*
* @author TMate Software Ltd.
* @version 1.3
* @since 1.2
*/
public class SVNPropertyValue implements Serializable {
private static final long serialVersionUID = 4845L;
private String myValue;
private byte[] myData;
/**
* Creates a new property value object from the given byte array.
*
* <p>
* This method is intended to instantiate binary property values. However if <code>propertyName</code> is of
* {@link SVNProperty#isSVNProperty(String) svn domain}, then it attempts
* to encode the passed bytes into a <code>String</code> value using the
* <span class="javastring">"UTF-8"</span> charset. Finally, the property value object is created via
* a call to {@link #create(String)}. In this way the text nature of the property is automatically
* preserved to avoid binary/text properties mess.
*
* @param propertyName property name
* @param data array containing property bytes
* @param offset offset in <code>data</code> to copy bytes from
* @param length amount of bytes to copy from <code>data</code>
* @return new property value object; <span class="javakeyword">null</span> if
* <code>data</code> is <span class="javakeyword">null</span>
*
*/
public static SVNPropertyValue create(String propertyName, byte[] data, int offset, int length) {
if (data == null) {
return null;
}
if (SVNProperty.isSVNProperty(propertyName)) {
String value;
try {
value = new String(data, offset, length, "UTF-8");
} catch (UnsupportedEncodingException e) {
value = new String(data, offset, length);
}
return new SVNPropertyValue(value);
}
return new SVNPropertyValue(data, offset, length);
}
/**
* Creates a new property value object from the given byte array.
*
* <p>
* This method is equivalent to <code>create(propertyName, data, 0, data.length)</code>.
*
* @param propertyName property name
* @param data array containing property bytes
* @return new property value object; <span class="javakeyword">null</span> if
* <code>data</code> is <span class="javakeyword">null</span>
* @see #create(String, byte[], int, int)
*/
public static SVNPropertyValue create(String propertyName, byte[] data) {
if (data == null) {
return null;
}
return create(propertyName, data, 0, data.length);
}
/**
* Creates a new property value object representing a text property value.
*
* <p/>
* This method is intended to create text property values only.
*
* @param propertyValue text property value which is stored as is
* @return new property value object; <span class="javakeyword">null</span> if
* <code>propertyValue</code> is <span class="javakeyword">null</span>
*/
public static SVNPropertyValue create(String propertyValue) {
if (propertyValue == null){
return null;
}
return new SVNPropertyValue(propertyValue);
}
/**
* Creates a new property value object representing a text property value.
*
* <p/>
* This method is intended to create text property values only.
*
* @param propertyValue text property value which is stored as is
* @return new property value object; <span class="javakeyword">null</span> if
* <code>propertyValue</code> is <span class="javakeyword">null</span>
*/
public static SVNPropertyValue create(char[] propertyValue, String encoding) {
if (propertyValue == null){
return null;
}
return new SVNPropertyValue(propertyValue, encoding);
}
/**
* Returns <code>byte[]</code> representation of <code>value</code>.
*
* <p/>
* If <code>value</code> is a {@link SVNPropertyValue#isString() string} property value, then bytes of
* the string are encoded using the <span class="javastring">"UTF-8"</span> charset and returned by this
* method. If encoding fails, then bytes are encoded using the default platform's charset.
*
* <p/>
* Otherwise, {@link SVNPropertyValue#getBytes()} is returned.
*
* @param value property value object
* @return bytes of the property value represented by <code>value</code>;
* <span class="javakeyword">null</span> if <code>value</code> is
* <span class="javakeyword">null</span>
*/
public static byte[] getPropertyAsBytes(SVNPropertyValue value) {
if (value == null) {
return null;
}
if (value.isString()) {
try {
return value.getString().getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
return value.getString().getBytes();
}
}
return value.getBytes();
}
/**
* Returns <code>String</code> representation of <code>value</code>.
*
* <p/>
* If <code>value</code> is a {@link SVNPropertyValue#isBinary() binary} property value, then its bytes are
* converted to a <code>String</code> encoding them with the <span class="javastring">"UTF-8"</span> charset
* and returned back to the caller. If that encoding fails, bytes are encoded with the default platform's
* charset.
*
* <p/>
* Otherwise, {@link SVNPropertyValue#getString()} is returned.
*
* @param value property value object
* @return string property value; <span class="javakeyword">null</span> if <code>value</code> is
* <span class="javakeyword">null</span>
*/
public static String getPropertyAsString(SVNPropertyValue value) {
if (value == null) {
return null;
}
if (value.isBinary()) {
try {
return new String(value.getBytes(), "UTF-8");
} catch (UnsupportedEncodingException e) {
return new String(value.getBytes());
}
}
return value.getString();
}
/**
* Returns <code>String</code> representation of <code>value</code>.
*
* <p/>
* If <code>value</code> is a {@link SVNPropertyValue#isBinary() binary} property value, then its bytes are
* converted to a <code>String</code> encoding them with the <span class="javastring">"UTF-8"</span> charset
* and returned back to the caller. If that encoding fails, bytes are encoded with the default platform's
* charset.
*
* <p/>
* Otherwise, {@link SVNPropertyValue#getString()} is returned.
*
* @param value property value object
* @return string property value; <span class="javakeyword">null</span> if <code>value</code> is
* <span class="javakeyword">null</span>
*/
public static char[] getPropertyAsChars(SVNPropertyValue value) {
if (value == null) {
return null;
}
if (value.isBinary()) {
return SVNEncodingUtil.getChars(value.getBytes(), "UTF-8");
}
return value.getString().toCharArray();
}
/**
* Says whether the property value wrapped by this object is binary or not.
* @return <span class="javakeyword">true</span> if binary, otherwise <span class="javakeyword">false</span>
*/
public boolean isBinary() {
return myData != null;
}
/**
* Returns property value bytes.
*
* <p/>
* Note: this will be always <span class="javakeyword">null</span> for <code>String</code> property values.
*
* @return byte array with property value bytes
*/
public byte[] getBytes() {
return myData;
}
/**
* Says whether the property value wrapped by this object is <code>String</code> or not.
* @return <span class="javakeyword">true</span> if textual, otherwise <span class="javakeyword">false</span>
*/
public boolean isString() {
return myValue != null;
}
/**
* Returns property value string.
*
* <p/>
* Note: this will be always <span class="javakeyword">null</span> for binary property values.
*
* @return property value string
*/
public String getString() {
return myValue;
}
/**
* Returns a string representation of this object.
*
* <p/>
* Note: irrelevant for binary properties.
*
* @return string representation of this object
*/
public String toString() {
if (isBinary()) {
return "property is binary";
}
return getString();
}
/**
* Says whether this object and <code>obj</code> are equal or not.
*
* @param obj object to compare with
* @return <span class="javakeyword">true</span> in the following cases:
* <ul>
* <li/><code>obj</code> is the same as this one (by reference)
* <li/>if <code>obj</code> is an <code>SVNPropertyValue</code> and either has got the same
* <code>String</code> value in case this object holds a <code>String</code> value, or
* the same byte array contents if this object represents a binary property value
* </ul>
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (obj instanceof SVNPropertyValue) {
SVNPropertyValue value = (SVNPropertyValue) obj;
if (isString()) {
return myValue.equals(getPropertyAsString(value));
} else if (isBinary()) {
return Arrays.equals(myData, getPropertyAsBytes(value));
}
}
return false;
}
/**
* Returns the hash code for this object. If this object represents a {@link #isString() string} property,
* then returns the hash code of the <code>String</code> object. Otherwise, this object represents
* a binary property and the hash code of the <code>byte[]</code> array is returned.
*
* @return hash code
*/
public int hashCode() {
if (myValue != null) {
return myValue.hashCode();
}
if (myData != null) {
return myData.hashCode();
}
return super.hashCode();
}
private SVNPropertyValue(byte[] data, int offset, int length) {
myData = new byte[length];
System.arraycopy(data, offset, myData, 0, length);
}
private SVNPropertyValue(String propertyValue) {
myValue = propertyValue;
}
private SVNPropertyValue(char[] propertyValue, String encoding) {
myData = SVNEncodingUtil.getBytes(propertyValue, encoding == null ? "UTF-8" : encoding);
}
public static boolean areEqual(SVNPropertyValue propertyValue1, SVNPropertyValue propertyValue2) {
if (propertyValue1 == null) {
return propertyValue2 == null;
}
if (propertyValue2 == null) {
return false;
}
byte[] propertyValueBytes1 = SVNPropertyValue.getPropertyAsBytes(propertyValue1);
byte[] propertyValueBytes2 = SVNPropertyValue.getPropertyAsBytes(propertyValue2);
return Arrays.equals(propertyValueBytes1, propertyValueBytes2);
}
public void clear() {
SVNEncodingUtil.clearArray(myData);
myValue = null;
}
}