View Javadoc
1   /*
2     (C) Copyright IBM Corp. 2007, 2009
3   
4     THIS FILE IS PROVIDED UNDER THE TERMS OF THE ECLIPSE PUBLIC LICENSE
5     ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE
6     CONSTITUTES RECIPIENTS ACCEPTANCE OF THE AGREEMENT.
7   
8     You can obtain a current copy of the Eclipse Public License from
9     http://www.opensource.org/licenses/eclipse-1.0.php
10  
11    @author : Endre Bak, IBM, ebak@de.ibm.com
12   * 
13   * Change History
14   * Flag       Date        Prog         Description
15   *------------------------------------------------------------------------------- 
16   * 1804402    2007-09-28  ebak         IPv6 ready SLP
17   * 2003590    2008-06-30  blaschke-oss Change licensing from CPL to EPL
18   * 2210455    2008-10-30  blaschke-oss Enhance javadoc, fix potential null pointers
19   * 2524131    2009-01-21  raman_arora  Upgrade client to JDK 1.5 (Phase 1)
20   * 2531371    2009-02-10  raman_arora  Upgrade client to JDK 1.5 (Phase 2) 
21   * 2797696    2009-05-27  raman_arora  Input files use unsafe operations
22   */
23  
24  package org.metricshub.wbem.sblim.slp.internal.msg;
25  
26  /*-
27   * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
28   * WBEM Java Client
29   * ჻჻჻჻჻჻
30   * Copyright 2023 - 2025 MetricsHub
31   * ჻჻჻჻჻჻
32   * Licensed under the Apache License, Version 2.0 (the "License");
33   * you may not use this file except in compliance with the License.
34   * You may obtain a copy of the License at
35   *
36   *      http://www.apache.org/licenses/LICENSE-2.0
37   *
38   * Unless required by applicable law or agreed to in writing, software
39   * distributed under the License is distributed on an "AS IS" BASIS,
40   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
41   * See the License for the specific language governing permissions and
42   * limitations under the License.
43   * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
44   */
45  
46  import java.io.ByteArrayOutputStream;
47  import java.util.ArrayList;
48  import java.util.Iterator;
49  import java.util.List;
50  import org.metricshub.wbem.sblim.slp.ServiceLocationAttribute;
51  import org.metricshub.wbem.sblim.slp.ServiceType;
52  import org.metricshub.wbem.sblim.slp.ServiceURL;
53  import org.metricshub.wbem.sblim.slp.internal.AttributeHandler;
54  import org.metricshub.wbem.sblim.slp.internal.Convert;
55  import org.metricshub.wbem.sblim.slp.internal.TRC;
56  
57  /**
58   * SLPOutputStream helps the building of SLP message bytes
59   *
60   */
61  public class SLPOutputStream {
62  	private static final int MAX_FIELD_SIZE = 65535;
63  
64  	private static final byte[] EMPTY_BYTES = new byte[0];
65  
66  	private ByteArrayOutputStream iOutStr = new ByteArrayOutputStream();
67  
68  	private int iStreamLimit;
69  
70  	/**
71  	 * Ctor.
72  	 */
73  	public SLPOutputStream() {
74  		this(Integer.MAX_VALUE);
75  	}
76  
77  	/**
78  	 * Ctor.
79  	 *
80  	 * @param pStreamLimit
81  	 */
82  	public SLPOutputStream(int pStreamLimit) {
83  		this.iStreamLimit = pStreamLimit <= 0 ? Integer.MAX_VALUE : pStreamLimit;
84  	}
85  
86  	/**
87  	 * size
88  	 *
89  	 * @return int
90  	 */
91  	public int size() {
92  		return this.iOutStr.size();
93  	}
94  
95  	/**
96  	 * freeSpace
97  	 *
98  	 * @return int
99  	 */
100 	public int freeSpace() {
101 		return this.iStreamLimit - this.iOutStr.size();
102 	}
103 
104 	/**
105 	 * toByteArray
106 	 *
107 	 * @return byte[]
108 	 */
109 	public byte[] toByteArray() {
110 		return this.iOutStr.toByteArray();
111 	}
112 
113 	/**
114 	 * write
115 	 *
116 	 * @param pBytes
117 	 * @return boolean
118 	 */
119 	public boolean write(byte[] pBytes) {
120 		if (freeSpace() < pBytes.length) return false;
121 		writeNoChk(pBytes);
122 		return true;
123 	}
124 
125 	/**
126 	 * write
127 	 *
128 	 * @param pServType
129 	 * @return boolean
130 	 */
131 	public boolean write(ServiceType pServType) {
132 		if (pServType == null) return write((String) null);
133 		return write(pServType.toString());
134 	}
135 
136 	/**
137 	 * URL_HDR_LENGTH
138 	 */
139 	public static final int URL_HDR_LENGTH = 6;
140 
141 	/*
142 	 * 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
143 	 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
144 	 * Reserved | Lifetime | URL Length |
145 	 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |URL
146 	 * len, contd.| URL (variable length) \
147 	 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |# of
148 	 * URL auths | Auth. blocks (if any) \
149 	 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
150 	 */
151 	/**
152 	 * @param pURL
153 	 * @return boolean
154 	 */
155 	public boolean write(ServiceURL pURL) {
156 		// URL strings in URL entries are not encoded
157 		String urlStr = pURL.toString();
158 		byte[] urlStrBytes = Convert.getBytes(urlStr);
159 		if (freeSpace() < URL_HDR_LENGTH + urlStrBytes.length) return false;
160 		writeNoChk8(0);
161 		writeNoChk16(pURL.getLifetime());
162 		writeNoChk16(urlStrBytes.length);
163 		writeNoChk(urlStrBytes);
164 		writeNoChk8(0);
165 		return true;
166 	}
167 
168 	/**
169 	 * writeURLList
170 	 *
171 	 * @param pURLList
172 	 * @return boolean
173 	 */
174 	@SuppressWarnings("null")
175 	public boolean writeURLList(List<?> pURLList) {
176 		int cnt = pURLList == null ? 0 : pURLList.size();
177 		if (cnt == 0) return write16(cnt);
178 		SLPOutputStream tmpStr = new SLPOutputStream();
179 		int i;
180 		for (i = 0; i < cnt; i++) {
181 			tmpStr.write((ServiceURL) pURLList.get(i));
182 			if (freeSpace() < tmpStr.size() + 2) break;
183 		}
184 		writeNoChk16(i);
185 		writeNoChk(tmpStr.toByteArray());
186 		return i == cnt;
187 	}
188 
189 	/**
190 	 * writeServTypeList
191 	 *
192 	 * @param pServTypeList
193 	 * @return boolean
194 	 */
195 	public boolean writeServTypeList(List<?> pServTypeList) {
196 		return writeServTypeList(pServTypeList == null ? null : pServTypeList.iterator());
197 	}
198 
199 	/**
200 	 * writeServTypeList
201 	 *
202 	 * @param pServTypeItr
203 	 * @return boolean
204 	 */
205 	public boolean writeServTypeList(Iterator<?> pServTypeItr) {
206 		if (pServTypeItr == null) return writeStringList((Iterator<String>) null);
207 		ArrayList<String> servTypeList = new ArrayList<String>();
208 		while (pServTypeItr.hasNext()) servTypeList.add(((ServiceType) pServTypeItr.next()).toString());
209 		return writeStringList(servTypeList);
210 	}
211 
212 	/**
213 	 * writeAttributeList
214 	 *
215 	 * @param pAttrList
216 	 * @return boolean
217 	 */
218 	public boolean writeAttributeList(List<?> pAttrList) {
219 		return writeAttributeList(pAttrList == null ? null : pAttrList.iterator());
220 	}
221 
222 	/**
223 	 * writeAttributeList
224 	 *
225 	 * @param pAttrItr
226 	 * @return boolean
227 	 */
228 	public boolean writeAttributeList(Iterator<?> pAttrItr) {
229 		if (pAttrItr == null) return writeStringList((Iterator<String>) null);
230 		ArrayList<String> attrStrList = new ArrayList<String>();
231 		while (pAttrItr.hasNext()) attrStrList.add(
232 			AttributeHandler.buildString((ServiceLocationAttribute) pAttrItr.next())
233 		);
234 		return writeStringList(attrStrList, null);
235 	}
236 
237 	/**
238 	 * # of AttrAuths |(if present) Attribute Authentication Blocks...
239 	 *
240 	 * @param pAuthBlockList
241 	 * @return boolean
242 	 */
243 	public boolean writeAuthBlockList(List<?> pAuthBlockList) {
244 		int cnt = pAuthBlockList == null ? 0 : pAuthBlockList.size();
245 		if (cnt != 0) TRC.error("Handling of non empty authentication block list is not implemented!");
246 		return write8(0);
247 	}
248 
249 	/**
250 	 * write
251 	 *
252 	 * @param pStr
253 	 * @return boolean
254 	 */
255 	public boolean write(String pStr) {
256 		return write(pStr, Convert.DEFAULT_RESERVED);
257 	}
258 
259 	/**
260 	 * write
261 	 *
262 	 * @param pStr
263 	 * @param pReservedChars
264 	 * @return boolean
265 	 */
266 	public boolean write(String pStr, String pReservedChars) {
267 		byte[] bytes = pStr == null ? EMPTY_BYTES : Convert.getBytes(Convert.escape(pStr, pReservedChars));
268 		if (bytes.length > MAX_FIELD_SIZE) return false;
269 		if (freeSpace() < bytes.length + 2) return false;
270 		writeNoChk16(bytes.length);
271 		writeNoChk(bytes);
272 		return true;
273 	}
274 
275 	/**
276 	 * writeStringList
277 	 *
278 	 * @param pStrList
279 	 * @return boolean
280 	 */
281 	public boolean writeStringList(List<String> pStrList) {
282 		return writeStringList(pStrList == null ? null : pStrList.iterator());
283 	}
284 
285 	/**
286 	 * writeStringList
287 	 *
288 	 * @param pStrListItr
289 	 * @return boolean
290 	 */
291 	public boolean writeStringList(Iterator<String> pStrListItr) {
292 		return writeStringList(pStrListItr, Convert.DEFAULT_RESERVED);
293 	}
294 
295 	/**
296 	 * writeStringList
297 	 *
298 	 * @param pStrList
299 	 * @param pReservedChars
300 	 * @return boolean
301 	 */
302 	public boolean writeStringList(List<String> pStrList, String pReservedChars) {
303 		return writeStringList(pStrList == null ? null : pStrList.iterator(), pReservedChars);
304 	}
305 
306 	/**
307 	 * writeStringList
308 	 *
309 	 * @param pStrListItr
310 	 * @param pReservedChars
311 	 * @return true if all list items are written to the stream, otherwise false
312 	 */
313 	public boolean writeStringList(Iterator<String> pStrListItr, String pReservedChars) {
314 		ByteArrayOutputStream listByteStr = new ByteArrayOutputStream();
315 		boolean first = true;
316 		boolean allWritten = true;
317 		if (pStrListItr != null) while (pStrListItr.hasNext()) {
318 			StringBuffer strBuf = new StringBuffer();
319 			String listItemStr = Convert.escape(pStrListItr.next(), pReservedChars);
320 			if (first) {
321 				first = false;
322 			} else {
323 				strBuf.append(',');
324 			}
325 			strBuf.append(listItemStr);
326 			byte[] listItemBytes = Convert.getBytes(strBuf.toString());
327 			int currentSize = listByteStr.size() + listItemBytes.length;
328 			if (currentSize > MAX_FIELD_SIZE || currentSize + 2 > freeSpace()) {
329 				allWritten = false;
330 				break;
331 			}
332 			listByteStr.write(listItemBytes, 0, listItemBytes.length);
333 		}
334 		byte[] listBytes = listByteStr.toByteArray();
335 		writeNoChk16(listBytes.length);
336 		writeNoChk(listBytes);
337 		return allWritten;
338 	}
339 
340 	/**
341 	 * write8
342 	 *
343 	 * @param pValue
344 	 * @return boolean
345 	 */
346 	public boolean write8(int pValue) {
347 		if (freeSpace() < 1) return false;
348 		writeNoChk8(pValue);
349 		return true;
350 	}
351 
352 	/**
353 	 * write16
354 	 *
355 	 * @param pValue
356 	 * @return boolean
357 	 */
358 	public boolean write16(int pValue) {
359 		if (freeSpace() < 2) return false;
360 		writeNoChk16(pValue);
361 		return true;
362 	}
363 
364 	/**
365 	 * write24
366 	 *
367 	 * @param pValue
368 	 * @return boolean
369 	 */
370 	public boolean write24(int pValue) {
371 		if (freeSpace() < 3) return false;
372 		writeNoChk24(pValue);
373 		return true;
374 	}
375 
376 	/**
377 	 * write32
378 	 *
379 	 * @param pValue
380 	 * @return boolean
381 	 */
382 	public boolean write32(long pValue) {
383 		if (freeSpace() < 4) return false;
384 		writeNoChk32(pValue);
385 		return true;
386 	}
387 
388 	/**
389 	 * writeNoChk
390 	 *
391 	 * @param pBytes
392 	 */
393 	public void writeNoChk(byte[] pBytes) {
394 		this.iOutStr.write(pBytes, 0, pBytes.length);
395 	}
396 
397 	/**
398 	 * writeNoChk8
399 	 *
400 	 * @param pValue
401 	 */
402 	public void writeNoChk8(int pValue) {
403 		this.iOutStr.write(pValue);
404 	}
405 
406 	/**
407 	 * writeNoChk16
408 	 *
409 	 * @param pValue
410 	 */
411 	public void writeNoChk16(int pValue) {
412 		this.iOutStr.write((pValue >> 8) & 0xff);
413 		this.iOutStr.write((pValue & 0xff));
414 	}
415 
416 	/**
417 	 * writeNoChk24
418 	 *
419 	 * @param pValue
420 	 */
421 	public void writeNoChk24(int pValue) {
422 		this.iOutStr.write((pValue >> 16) & 0xff);
423 		writeNoChk16(pValue);
424 	}
425 
426 	/**
427 	 * writeNoChk32
428 	 *
429 	 * @param pValue
430 	 */
431 	public void writeNoChk32(long pValue) {
432 		this.iOutStr.write((int) ((pValue >> 24) & 0xff));
433 		writeNoChk24((int) pValue);
434 	}
435 }