Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SerialBlob.java
40948 views
1
/*
2
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package javax.sql.rowset.serial;
27
28
import java.sql.*;
29
import java.io.*;
30
import java.lang.reflect.*;
31
import java.util.Arrays;
32
33
34
/**
35
* A serialized mapping in the Java programming language of an SQL
36
* <code>BLOB</code> value.
37
* <P>
38
* The <code>SerialBlob</code> class provides a constructor for creating
39
* an instance from a <code>Blob</code> object. Note that the
40
* <code>Blob</code>
41
* object should have brought the SQL <code>BLOB</code> value's data over
42
* to the client before a <code>SerialBlob</code> object
43
* is constructed from it. The data of an SQL <code>BLOB</code> value can
44
* be materialized on the client as an array of bytes (using the method
45
* <code>Blob.getBytes</code>) or as a stream of uninterpreted bytes
46
* (using the method <code>Blob.getBinaryStream</code>).
47
* <P>
48
* <code>SerialBlob</code> methods make it possible to make a copy of a
49
* <code>SerialBlob</code> object as an array of bytes or as a stream.
50
* They also make it possible to locate a given pattern of bytes or a
51
* <code>Blob</code> object within a <code>SerialBlob</code> object
52
* and to update or truncate a <code>Blob</code> object.
53
*
54
* <h2> Thread safety </h2>
55
*
56
* <p> A SerialBlob is not safe for use by multiple concurrent threads. If a
57
* SerialBlob is to be used by more than one thread then access to the SerialBlob
58
* should be controlled by appropriate synchronization.
59
*
60
* @author Jonathan Bruce
61
* @since 1.5
62
*/
63
public class SerialBlob implements Blob, Serializable, Cloneable {
64
65
/**
66
* A serialized array of uninterpreted bytes representing the
67
* value of this <code>SerialBlob</code> object.
68
* @serial
69
*/
70
private byte[] buf;
71
72
/**
73
* The internal representation of the <code>Blob</code> object on which this
74
* <code>SerialBlob</code> object is based.
75
*/
76
@SuppressWarnings("serial") // Not statically typed as Serializable; checked in writeObject
77
private Blob blob;
78
79
/**
80
* The number of bytes in this <code>SerialBlob</code> object's
81
* array of bytes.
82
* @serial
83
*/
84
private long len;
85
86
/**
87
* The original number of bytes in this <code>SerialBlob</code> object's
88
* array of bytes when it was first established.
89
* @serial
90
*/
91
private long origLen;
92
93
/**
94
* Constructs a <code>SerialBlob</code> object that is a serialized version of
95
* the given <code>byte</code> array.
96
* <p>
97
* The new <code>SerialBlob</code> object is initialized with the data from the
98
* <code>byte</code> array, thus allowing disconnected <code>RowSet</code>
99
* objects to establish serialized <code>Blob</code> objects without
100
* touching the data source.
101
*
102
* @param b the <code>byte</code> array containing the data for the
103
* <code>Blob</code> object to be serialized
104
* @throws SerialException if an error occurs during serialization
105
* @throws SQLException if a SQL errors occurs
106
*/
107
public SerialBlob(byte[] b)
108
throws SerialException, SQLException {
109
110
len = b.length;
111
buf = new byte[(int)len];
112
for(int i = 0; i < len; i++) {
113
buf[i] = b[i];
114
}
115
origLen = len;
116
}
117
118
119
/**
120
* Constructs a <code>SerialBlob</code> object that is a serialized
121
* version of the given <code>Blob</code> object.
122
* <P>
123
* The new <code>SerialBlob</code> object is initialized with the
124
* data from the <code>Blob</code> object; therefore, the
125
* <code>Blob</code> object should have previously brought the
126
* SQL <code>BLOB</code> value's data over to the client from
127
* the database. Otherwise, the new <code>SerialBlob</code> object
128
* will contain no data.
129
*
130
* @param blob the <code>Blob</code> object from which this
131
* <code>SerialBlob</code> object is to be constructed;
132
* cannot be null.
133
* @throws SerialException if an error occurs during serialization
134
* @throws SQLException if the <code>Blob</code> passed to this
135
* to this constructor is a <code>null</code>.
136
* @see java.sql.Blob
137
*/
138
public SerialBlob (Blob blob)
139
throws SerialException, SQLException {
140
141
if (blob == null) {
142
throw new SQLException(
143
"Cannot instantiate a SerialBlob object with a null Blob object");
144
}
145
146
len = blob.length();
147
buf = blob.getBytes(1, (int)len );
148
this.blob = blob;
149
origLen = len;
150
}
151
152
/**
153
* Copies the specified number of bytes, starting at the given
154
* position, from this <code>SerialBlob</code> object to
155
* another array of bytes.
156
* <P>
157
* Note that if the given number of bytes to be copied is larger than
158
* the length of this <code>SerialBlob</code> object's array of
159
* bytes, the given number will be shortened to the array's length.
160
*
161
* @param pos the ordinal position of the first byte in this
162
* <code>SerialBlob</code> object to be copied;
163
* numbering starts at <code>1</code>; must not be less
164
* than <code>1</code> and must be less than or equal
165
* to the length of this <code>SerialBlob</code> object
166
* @param length the number of bytes to be copied
167
* @return an array of bytes that is a copy of a region of this
168
* <code>SerialBlob</code> object, starting at the given
169
* position and containing the given number of consecutive bytes
170
* @throws SerialException if the given starting position is out of bounds;
171
* if {@code free} had previously been called on this object
172
*/
173
public byte[] getBytes(long pos, int length) throws SerialException {
174
isValid();
175
if (length > len) {
176
length = (int)len;
177
}
178
179
if (pos < 1 || len - pos < 0 ) {
180
throw new SerialException("Invalid arguments: position cannot be "
181
+ "less than 1 or greater than the length of the SerialBlob");
182
}
183
184
pos--; // correct pos to array index
185
186
byte[] b = new byte[length];
187
188
for (int i = 0; i < length; i++) {
189
b[i] = this.buf[(int)pos];
190
pos++;
191
}
192
return b;
193
}
194
195
/**
196
* Retrieves the number of bytes in this <code>SerialBlob</code>
197
* object's array of bytes.
198
*
199
* @return a <code>long</code> indicating the length in bytes of this
200
* <code>SerialBlob</code> object's array of bytes
201
* @throws SerialException if an error occurs;
202
* if {@code free} had previously been called on this object
203
*/
204
public long length() throws SerialException {
205
isValid();
206
return len;
207
}
208
209
/**
210
* Returns this <code>SerialBlob</code> object as an input stream.
211
* Unlike the related method, <code>setBinaryStream</code>,
212
* a stream is produced regardless of whether the <code>SerialBlob</code>
213
* was created with a <code>Blob</code> object or a <code>byte</code> array.
214
*
215
* @return a <code>java.io.InputStream</code> object that contains
216
* this <code>SerialBlob</code> object's array of bytes
217
* @throws SerialException if an error occurs;
218
* if {@code free} had previously been called on this object
219
* @see #setBinaryStream
220
*/
221
public java.io.InputStream getBinaryStream() throws SerialException {
222
isValid();
223
InputStream stream = new ByteArrayInputStream(buf);
224
return stream;
225
}
226
227
/**
228
* Returns the position in this <code>SerialBlob</code> object where
229
* the given pattern of bytes begins, starting the search at the
230
* specified position.
231
*
232
* @param pattern the pattern of bytes for which to search
233
* @param start the position of the byte in this
234
* <code>SerialBlob</code> object from which to begin
235
* the search; the first position is <code>1</code>;
236
* must not be less than <code>1</code> nor greater than
237
* the length of this <code>SerialBlob</code> object
238
* @return the position in this <code>SerialBlob</code> object
239
* where the given pattern begins, starting at the specified
240
* position; <code>-1</code> if the pattern is not found
241
* or the given starting position is out of bounds; position
242
* numbering for the return value starts at <code>1</code>
243
* @throws SerialException if an error occurs when serializing the blob;
244
* if {@code free} had previously been called on this object
245
* @throws SQLException if there is an error accessing the <code>BLOB</code>
246
* value from the database
247
*/
248
public long position(byte[] pattern, long start)
249
throws SerialException, SQLException {
250
251
isValid();
252
if (start < 1 || start > len) {
253
return -1;
254
}
255
256
int pos = (int)start-1; // internally Blobs are stored as arrays.
257
int i = 0;
258
long patlen = pattern.length;
259
260
while (pos < len) {
261
if (pattern[i] == buf[pos]) {
262
if (i + 1 == patlen) {
263
return (pos + 1) - (patlen - 1);
264
}
265
i++; pos++; // increment pos, and i
266
} else if (pattern[i] != buf[pos]) {
267
pos++; // increment pos only
268
}
269
}
270
return -1; // not found
271
}
272
273
/**
274
* Returns the position in this <code>SerialBlob</code> object where
275
* the given <code>Blob</code> object begins, starting the search at the
276
* specified position.
277
*
278
* @param pattern the <code>Blob</code> object for which to search;
279
* @param start the position of the byte in this
280
* <code>SerialBlob</code> object from which to begin
281
* the search; the first position is <code>1</code>;
282
* must not be less than <code>1</code> nor greater than
283
* the length of this <code>SerialBlob</code> object
284
* @return the position in this <code>SerialBlob</code> object
285
* where the given <code>Blob</code> object begins, starting
286
* at the specified position; <code>-1</code> if the pattern is
287
* not found or the given starting position is out of bounds;
288
* position numbering for the return value starts at <code>1</code>
289
* @throws SerialException if an error occurs when serializing the blob;
290
* if {@code free} had previously been called on this object
291
* @throws SQLException if there is an error accessing the <code>BLOB</code>
292
* value from the database
293
*/
294
public long position(Blob pattern, long start)
295
throws SerialException, SQLException {
296
isValid();
297
return position(pattern.getBytes(1, (int)(pattern.length())), start);
298
}
299
300
/**
301
* Writes the given array of bytes to the <code>BLOB</code> value that
302
* this <code>Blob</code> object represents, starting at position
303
* <code>pos</code>, and returns the number of bytes written.
304
*
305
* @param pos the position in the SQL <code>BLOB</code> value at which
306
* to start writing. The first position is <code>1</code>;
307
* must not be less than <code>1</code> nor greater than
308
* the length of this <code>SerialBlob</code> object.
309
* @param bytes the array of bytes to be written to the <code>BLOB</code>
310
* value that this <code>Blob</code> object represents
311
* @return the number of bytes written
312
* @throws SerialException if there is an error accessing the
313
* <code>BLOB</code> value; or if an invalid position is set; if an
314
* invalid offset value is set;
315
* if {@code free} had previously been called on this object
316
* @throws SQLException if there is an error accessing the <code>BLOB</code>
317
* value from the database
318
* @see #getBytes
319
*/
320
public int setBytes(long pos, byte[] bytes)
321
throws SerialException, SQLException {
322
return setBytes(pos, bytes, 0, bytes.length);
323
}
324
325
/**
326
* Writes all or part of the given <code>byte</code> array to the
327
* <code>BLOB</code> value that this <code>Blob</code> object represents
328
* and returns the number of bytes written.
329
* Writing starts at position <code>pos</code> in the <code>BLOB</code>
330
* value; <i>len</i> bytes from the given byte array are written.
331
*
332
* @param pos the position in the <code>BLOB</code> object at which
333
* to start writing. The first position is <code>1</code>;
334
* must not be less than <code>1</code> nor greater than
335
* the length of this <code>SerialBlob</code> object.
336
* @param bytes the array of bytes to be written to the <code>BLOB</code>
337
* value
338
* @param offset the offset in the <code>byte</code> array at which
339
* to start reading the bytes. The first offset position is
340
* <code>0</code>; must not be less than <code>0</code> nor greater
341
* than the length of the <code>byte</code> array
342
* @param length the number of bytes to be written to the
343
* <code>BLOB</code> value from the array of bytes <i>bytes</i>.
344
*
345
* @return the number of bytes written
346
* @throws SerialException if there is an error accessing the
347
* <code>BLOB</code> value; if an invalid position is set; if an
348
* invalid offset value is set; if number of bytes to be written
349
* is greater than the <code>SerialBlob</code> length; or the combined
350
* values of the length and offset is greater than the Blob buffer;
351
* if {@code free} had previously been called on this object
352
* @throws SQLException if there is an error accessing the <code>BLOB</code>
353
* value from the database.
354
* @see #getBytes
355
*/
356
public int setBytes(long pos, byte[] bytes, int offset, int length)
357
throws SerialException, SQLException {
358
359
isValid();
360
if (offset < 0 || offset > bytes.length) {
361
throw new SerialException("Invalid offset in byte array set");
362
}
363
364
if (pos < 1 || pos > this.length()) {
365
throw new SerialException("Invalid position in BLOB object set");
366
}
367
368
if ((long)(length) > origLen) {
369
throw new SerialException("Buffer is not sufficient to hold the value");
370
}
371
372
if ((length + offset) > bytes.length) {
373
throw new SerialException("Invalid OffSet. Cannot have combined offset " +
374
"and length that is greater that the Blob buffer");
375
}
376
377
int i = 0;
378
pos--; // correct to array indexing
379
while ( i < length || (offset + i +1) < (bytes.length-offset) ) {
380
this.buf[(int)pos + i] = bytes[offset + i ];
381
i++;
382
}
383
return i;
384
}
385
386
/**
387
* Retrieves a stream that can be used to write to the <code>BLOB</code>
388
* value that this <code>Blob</code> object represents. The stream begins
389
* at position <code>pos</code>. This method forwards the
390
* <code>setBinaryStream()</code> call to the underlying <code>Blob</code> in
391
* the event that this <code>SerialBlob</code> object is instantiated with a
392
* <code>Blob</code>. If this <code>SerialBlob</code> is instantiated with
393
* a <code>byte</code> array, a <code>SerialException</code> is thrown.
394
*
395
* @param pos the position in the <code>BLOB</code> value at which
396
* to start writing
397
* @return a <code>java.io.OutputStream</code> object to which data can
398
* be written
399
* @throws SQLException if there is an error accessing the
400
* <code>BLOB</code> value
401
* @throws SerialException if the SerialBlob in not instantiated with a
402
* <code>Blob</code> object that supports <code>setBinaryStream()</code>;
403
* if {@code free} had previously been called on this object
404
* @see #getBinaryStream
405
*/
406
public java.io.OutputStream setBinaryStream(long pos)
407
throws SerialException, SQLException {
408
409
isValid();
410
if (this.blob != null) {
411
return this.blob.setBinaryStream(pos);
412
} else {
413
throw new SerialException("Unsupported operation. SerialBlob cannot " +
414
"return a writable binary stream, unless instantiated with a Blob object " +
415
"that provides a setBinaryStream() implementation");
416
}
417
}
418
419
/**
420
* Truncates the <code>BLOB</code> value that this <code>Blob</code>
421
* object represents to be <code>len</code> bytes in length.
422
*
423
* @param length the length, in bytes, to which the <code>BLOB</code>
424
* value that this <code>Blob</code> object represents should be
425
* truncated
426
* @throws SerialException if there is an error accessing the Blob value;
427
* or the length to truncate is greater that the SerialBlob length;
428
* if {@code free} had previously been called on this object
429
*/
430
public void truncate(long length) throws SerialException {
431
isValid();
432
if (length > len) {
433
throw new SerialException(
434
"Length more than what can be truncated");
435
} else if((int)length == 0) {
436
buf = new byte[0];
437
len = length;
438
} else {
439
len = length;
440
buf = this.getBytes(1, (int)len);
441
}
442
}
443
444
445
/**
446
* Returns an
447
* <code>InputStream</code> object that contains a partial
448
* {@code Blob} value, starting with the byte specified by pos, which is
449
* length bytes in length.
450
*
451
* @param pos the offset to the first byte of the partial value to be
452
* retrieved. The first byte in the {@code Blob} is at position 1
453
* @param length the length in bytes of the partial value to be retrieved
454
* @return
455
* <code>InputStream</code> through which the partial {@code Blob} value can
456
* be read.
457
* @throws SQLException if pos is less than 1 or if pos is greater than the
458
* number of bytes in the {@code Blob} or if pos + length is greater than
459
* the number of bytes in the {@code Blob}
460
* @throws SerialException if the {@code free} method had been previously
461
* called on this object
462
*
463
* @since 1.6
464
*/
465
public InputStream getBinaryStream(long pos, long length) throws SQLException {
466
isValid();
467
if (pos < 1 || pos > this.length()) {
468
throw new SerialException("Invalid position in BLOB object set");
469
}
470
if (length < 1 || length > len - pos + 1) {
471
throw new SerialException(
472
"length is < 1 or pos + length > total number of bytes");
473
}
474
return new ByteArrayInputStream(buf, (int) pos - 1, (int) length);
475
}
476
477
478
/**
479
* This method frees the {@code SerialBlob} object and releases the
480
* resources that it holds. The object is invalid once the {@code free}
481
* method is called. <p> If {@code free} is called multiple times, the
482
* subsequent calls to {@code free} are treated as a no-op. </P>
483
*
484
* @throws SQLException if an error occurs releasing the Blob's resources
485
* @since 1.6
486
*/
487
public void free() throws SQLException {
488
if (buf != null) {
489
buf = null;
490
if (blob != null) {
491
blob.free();
492
}
493
blob = null;
494
}
495
}
496
497
/**
498
* Compares this SerialBlob to the specified object. The result is {@code
499
* true} if and only if the argument is not {@code null} and is a {@code
500
* SerialBlob} object that represents the same sequence of bytes as this
501
* object.
502
*
503
* @param obj The object to compare this {@code SerialBlob} against
504
*
505
* @return {@code true} if the given object represents a {@code SerialBlob}
506
* equivalent to this SerialBlob, {@code false} otherwise
507
*
508
*/
509
public boolean equals(Object obj) {
510
if (this == obj) {
511
return true;
512
}
513
if (obj instanceof SerialBlob) {
514
SerialBlob sb = (SerialBlob)obj;
515
if (this.len == sb.len) {
516
return Arrays.equals(buf, sb.buf);
517
}
518
}
519
return false;
520
}
521
522
/**
523
* Returns a hash code for this {@code SerialBlob}.
524
* @return a hash code value for this object.
525
*/
526
public int hashCode() {
527
return ((31 + Arrays.hashCode(buf)) * 31 + (int)len) * 31 + (int)origLen;
528
}
529
530
/**
531
* Returns a clone of this {@code SerialBlob}. The copy will contain a
532
* reference to a clone of the internal byte array, not a reference
533
* to the original internal byte array of this {@code SerialBlob} object.
534
* The underlying {@code Blob} object will be set to null.
535
*
536
* @return a clone of this SerialBlob
537
*/
538
public Object clone() {
539
try {
540
SerialBlob sb = (SerialBlob) super.clone();
541
sb.buf = (buf != null) ? Arrays.copyOf(buf, (int)len) : null;
542
sb.blob = null;
543
return sb;
544
} catch (CloneNotSupportedException ex) {
545
// this shouldn't happen, since we are Cloneable
546
throw new InternalError();
547
}
548
}
549
550
/**
551
* readObject is called to restore the state of the SerialBlob from
552
* a stream.
553
* @param s the {@code ObjectInputStream} to read from.
554
*
555
* @throws ClassNotFoundException if the class of a serialized object
556
* could not be found.
557
* @throws IOException if an I/O error occurs.
558
*/
559
private void readObject(ObjectInputStream s)
560
throws IOException, ClassNotFoundException {
561
562
ObjectInputStream.GetField fields = s.readFields();
563
byte[] tmp = (byte[])fields.get("buf", null);
564
if (tmp == null)
565
throw new InvalidObjectException("buf is null and should not be!");
566
buf = tmp.clone();
567
len = fields.get("len", 0L);
568
if (buf.length != len)
569
throw new InvalidObjectException("buf is not the expected size");
570
origLen = fields.get("origLen", 0L);
571
blob = (Blob) fields.get("blob", null);
572
}
573
574
/**
575
* writeObject is called to save the state of the SerialBlob
576
* to a stream.
577
* @param s the {@code ObjectOutputStream} to write to.
578
* @throws IOException if an I/O error occurs.
579
*/
580
private void writeObject(ObjectOutputStream s)
581
throws IOException {
582
583
ObjectOutputStream.PutField fields = s.putFields();
584
fields.put("buf", buf);
585
fields.put("len", len);
586
fields.put("origLen", origLen);
587
// Note: this check to see if it is an instance of Serializable
588
// is for backwards compatibility
589
fields.put("blob", blob instanceof Serializable ? blob : null);
590
s.writeFields();
591
}
592
593
/**
594
* Check to see if this object had previously had its {@code free} method
595
* called
596
*
597
* @throws SerialException
598
*/
599
private void isValid() throws SerialException {
600
if (buf == null) {
601
throw new SerialException("Error: You cannot call a method on a " +
602
"SerialBlob instance once free() has been called.");
603
}
604
}
605
606
/**
607
* The identifier that assists in the serialization of this
608
* {@code SerialBlob} object.
609
*/
610
static final long serialVersionUID = -8144641928112860441L;
611
}
612
613