1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 using System;
19 
20 using TokenStream = Lucene.Net.Analysis.TokenStream;
21 using ArrayUtil = Lucene.Net.Util.ArrayUtil;
22 
23 namespace Lucene.Net.Index
24 {
25 
26 	/// <summary>  A Payload is metadata that can be stored together with each occurrence
27 	/// of a term. This metadata is stored inline in the posting list of the
28 	/// specific term.
29 	/// <p/>
30 	/// To store payloads in the index a <see cref="TokenStream"/> has to be used that
31 	/// produces payload data.
32 	/// <p/>
33     /// Use <see cref="TermPositions.PayloadLength"/> and <see cref="TermPositions.GetPayload(byte[], int)"/>
34 	/// to retrieve the payloads from the index.<br/>
35 	///
36 	/// </summary>
37 	[Serializable]
38 	public class Payload : System.ICloneable
39 	{
40 		/// <summary>the byte array containing the payload data </summary>
41 		protected internal byte[] data;
42 
43 		/// <summary>the offset within the byte array </summary>
44 		protected internal int internalOffset;
45 
46 		/// <summary>the length of the payload data </summary>
47 		protected internal int internalLength;
48 
49 		/// <summary>Creates an empty payload and does not allocate a byte array. </summary>
Payload()50 		public Payload()
51 		{
52 			// nothing to do
53 		}
54 
55 		/// <summary> Creates a new payload with the the given array as data.
56 		/// A reference to the passed-in array is held, i. e. no
57 		/// copy is made.
58 		///
59 		/// </summary>
60 		/// <param name="data">the data of this payload
61 		/// </param>
Payload(byte[] data)62 		public Payload(byte[] data):this(data, 0, data.Length)
63 		{
64 		}
65 
66 		/// <summary> Creates a new payload with the the given array as data.
67 		/// A reference to the passed-in array is held, i. e. no
68 		/// copy is made.
69 		///
70 		/// </summary>
71 		/// <param name="data">the data of this payload
72 		/// </param>
73 		/// <param name="offset">the offset in the data byte array
74 		/// </param>
75 		/// <param name="length">the length of the data
76 		/// </param>
Payload(byte[] data, int offset, int length)77 		public Payload(byte[] data, int offset, int length)
78 		{
79 			if (offset < 0 || offset + length > data.Length)
80 			{
81 				throw new System.ArgumentException();
82 			}
83 			this.data = data;
84 			this.internalOffset = offset;
85 			this.internalLength = length;
86 		}
87 
88 	    /// <summary> Sets this payloads data.
89 		/// A reference to the passed-in array is held, i. e. no
90 		/// copy is made.
91 		/// </summary>
SetData(byte[] value, int offset, int length)92 		public virtual void  SetData(byte[] value, int offset, int length)
93 		{
94 			this.data = value;
95 			this.internalOffset = offset;
96 			this.internalLength = length;
97 		}
98 
99 	    /// <summary> Gets or sets a reference to the underlying byte array
100 	    /// that holds this payloads data.  Data is not copied.
101 	    /// </summary>
SetData(byte[] value)102 	    public virtual void SetData(byte[] value)
103 	    {
104 	        SetData(value, 0, value.Length);
105 	    }
106 
107 	    /// <summary> Gets or sets a reference to the underlying byte array
108 	    /// that holds this payloads data.  Data is not copied.
109 	    /// </summary>
GetData()110 	    public virtual byte[] GetData()
111 	    {
112 	        return this.data;
113 	    }
114 
115 	    /// <summary> Returns the offset in the underlying byte array </summary>
116 	    public virtual int Offset
117 	    {
118 	        get { return this.internalOffset; }
119 	    }
120 
121 	    /// <summary> Returns the length of the payload data. </summary>
122 	    public virtual int Length
123 	    {
124 	        get { return this.internalLength; }
125 	    }
126 
127 	    /// <summary> Returns the byte at the given index.</summary>
ByteAt(int index)128 		public virtual byte ByteAt(int index)
129 		{
130 			if (0 <= index && index < this.internalLength)
131 			{
132 				return this.data[this.internalOffset + index];
133 			}
134 			throw new System. IndexOutOfRangeException("Index of bound " + index);
135 		}
136 
137 		/// <summary> Allocates a new byte array, copies the payload data into it and returns it. </summary>
ToByteArray()138 		public virtual byte[] ToByteArray()
139 		{
140 			byte[] retArray = new byte[this.internalLength];
141 			Array.Copy(this.data, this.internalOffset, retArray, 0, this.internalLength);
142 			return retArray;
143 		}
144 
145 		/// <summary> Copies the payload data to a byte array.
146 		///
147 		/// </summary>
148 		/// <param name="target">the target byte array
149 		/// </param>
150 		/// <param name="targetOffset">the offset in the target byte array
151 		/// </param>
CopyTo(byte[] target, int targetOffset)152 		public virtual void  CopyTo(byte[] target, int targetOffset)
153 		{
154 			if (this.internalLength > target.Length + targetOffset)
155 			{
156 				throw new System.IndexOutOfRangeException();
157 			}
158 			Array.Copy(this.data, this.internalOffset, target, targetOffset, this.internalLength);
159 		}
160 
161 		/// <summary> Clones this payload by creating a copy of the underlying
162 		/// byte array.
163 		/// </summary>
Clone()164 		public virtual System.Object Clone()
165 		{
166 			try
167 			{
168 				// Start with a shallow copy of data
169 				Payload clone = (Payload) base.MemberwiseClone();
170 				// Only copy the part of data that belongs to this Payload
171 				if (internalOffset == 0 && internalLength == data.Length)
172 				{
173 					// It is the whole thing, so just clone it.
174 					clone.data = new byte[data.Length];
175 					data.CopyTo(clone.data, 0);
176 				}
177 				else
178 				{
179 					// Just get the part
180 					clone.data = this.ToByteArray();
181 					clone.internalOffset = 0;
182 				}
183 				return clone;
184 			}
185 			catch (System.Exception e)
186 			{
187 				throw new System.SystemException(e.Message, e); // shouldn't happen
188 			}
189 		}
190 
Equals(System.Object obj)191 		public  override bool Equals(System.Object obj)
192 		{
193 			if (obj == this)
194 				return true;
195 			if (obj is Payload)
196 			{
197 				Payload other = (Payload) obj;
198 				if (internalLength == other.internalLength)
199 				{
200 					for (int i = 0; i < internalLength; i++)
201 						if (data[internalOffset + i] != other.data[other.internalOffset + i])
202 							return false;
203 					return true;
204 				}
205 				else
206 					return false;
207 			}
208 			else
209 				return false;
210 		}
211 
GetHashCode()212 		public override int GetHashCode()
213 		{
214 			return ArrayUtil.HashCode(data, internalOffset, internalOffset + internalLength);
215 		}
216 	}
217 }