1 21 22 package org.apache.derby.iapi.types; 23 24 import java.io.InputStream ; 25 import java.io.IOException ; 26 import java.io.EOFException ; 27 import java.io.Reader ; 28 import java.io.UTFDataFormatException ; 29 import org.apache.derby.iapi.reference.SQLState; 30 import org.apache.derby.iapi.services.i18n.MessageService; 31 import org.apache.derby.iapi.services.io.DerbyIOException; 32 import org.apache.derby.iapi.services.io.LimitReader; 33 import org.apache.derby.iapi.types.TypeId; 34 35 39 public final class ReaderToUTF8Stream 40 extends InputStream 41 { 42 45 private LimitReader reader; 46 47 private byte[] buffer; 48 private int boff; 49 private int blen; 50 private boolean eof; 51 private boolean multipleBuffer; 52 private final static int BUFSIZE = 32768; 55 56 61 private final int charsToTruncate; 62 private static final char SPACE = ' '; 63 64 71 private final int valueLength; 72 73 private final int maximumLength; 74 75 private final String typeName; 76 77 90 public ReaderToUTF8Stream(Reader appReader, 91 int valueLength, 92 int numCharsToTruncate, 93 String typeName) { 94 this.reader = new LimitReader(appReader); 95 reader.setLimit(valueLength); 96 buffer = new byte[BUFSIZE]; 97 blen = -1; 98 this.charsToTruncate = numCharsToTruncate; 99 this.valueLength = valueLength; 100 this.maximumLength = -1; 101 this.typeName = typeName; 102 } 103 104 118 public ReaderToUTF8Stream(Reader appReader, 119 int maximumLength, 120 String typeName) { 121 if (maximumLength < 0) { 122 throw new IllegalArgumentException ("Maximum length for a capped " + 123 "stream cannot be negative: " + maximumLength); 124 } 125 if (typeName == null) { 126 throw new IllegalArgumentException ("Type name cannot be null"); 127 } 128 this.reader = new LimitReader(appReader); 129 reader.setLimit(maximumLength); 130 buffer = new byte[BUFSIZE]; 131 blen = -1; 132 this.maximumLength = maximumLength; 133 this.typeName = typeName; 134 this.charsToTruncate = -1; 135 this.valueLength = -1; 136 } 137 138 144 public int read() throws IOException { 145 146 if ( buffer == null) 151 throw new EOFException (MessageService.getTextMessage(SQLState.STREAM_EOF)); 152 153 154 if (blen < 0) 156 fillBuffer(2); 157 158 while (boff == blen) 159 { 160 if (eof) 162 { 163 close(); 167 return -1; 168 } 169 170 171 fillBuffer(0); 172 } 173 174 return buffer[boff++] & 0xff; 175 176 } 177 178 public int read(byte b[], int off, int len) throws IOException { 179 180 if ( buffer == null ) 185 throw new EOFException (MessageService.getTextMessage 186 (SQLState.STREAM_EOF)); 187 188 if (blen < 0) 190 fillBuffer(2); 191 192 int readCount = 0; 193 194 while (len > 0) 195 { 196 197 int copyBytes = blen - boff; 198 199 if (copyBytes == 0) 201 { 202 if (eof) 203 { 204 if (readCount > 0) 205 { 206 return readCount; 207 } 208 else 209 { 210 close(); 212 return -1; 213 } 214 215 } 216 fillBuffer(0); 217 continue; 218 } 219 220 if (len < copyBytes) 221 copyBytes = len; 222 223 System.arraycopy(buffer, boff, b, off, copyBytes); 224 boff += copyBytes; 225 len -= copyBytes; 226 readCount += copyBytes; 227 off += copyBytes; 228 229 } 230 return readCount; 231 } 232 233 private void fillBuffer(int startingOffset) throws IOException 234 { 235 int off = boff = startingOffset; 236 237 if (off == 0) 238 multipleBuffer = true; 239 240 for (; off <= buffer.length - 6; ) 243 { 244 int c = reader.read(); 245 if (c < 0) { 246 eof = true; 247 break; 248 } 249 250 if ((c >= 0x0001) && (c <= 0x007F)) 251 { 252 buffer[off++] = (byte) c; 253 } 254 else if (c > 0x07FF) 255 { 256 buffer[off++] = (byte) (0xE0 | ((c >> 12) & 0x0F)); 257 buffer[off++] = (byte) (0x80 | ((c >> 6) & 0x3F)); 258 buffer[off++] = (byte) (0x80 | ((c >> 0) & 0x3F)); 259 } 260 else 261 { 262 buffer[off++] = (byte) (0xC0 | ((c >> 6) & 0x1F)); 263 buffer[off++] = (byte) (0x80 | ((c >> 0) & 0x3F)); 264 } 265 } 266 267 blen = off; 268 boff = 0; 269 270 if (eof) 271 checkSufficientData(); 272 } 273 274 287 private void checkSufficientData() throws IOException 288 { 289 if (charsToTruncate > 0) 292 { 293 reader.setLimit(charsToTruncate); 294 truncate(); 295 } 296 297 int remainingBytes = reader.clearLimit(); 300 if (remainingBytes > 0 && valueLength > 0) { 301 throw new DerbyIOException( 303 MessageService.getTextMessage( 304 SQLState.SET_STREAM_INEXACT_LENGTH_DATA), 305 SQLState.SET_STREAM_INEXACT_LENGTH_DATA); 306 } 307 308 if (remainingBytes == 0 && reader.read() >= 0) { 312 if (valueLength > -1) { 313 throw new DerbyIOException( 314 MessageService.getTextMessage( 315 SQLState.SET_STREAM_INEXACT_LENGTH_DATA), 316 SQLState.SET_STREAM_INEXACT_LENGTH_DATA); 317 } else { 318 if (canTruncate()) { 321 truncate(); 322 } else { 323 throw new DerbyIOException( 324 MessageService.getTextMessage( 325 SQLState.LANG_STRING_TRUNCATION), 326 SQLState.LANG_STRING_TRUNCATION); 327 } 328 } 329 } 330 331 if (!multipleBuffer) 333 { 334 int utflen = blen - 2; 335 336 buffer[0] = (byte) ((utflen >>> 8) & 0xFF); 337 buffer[1] = (byte) ((utflen >>> 0) & 0xFF); 338 339 } 340 else 341 { 342 buffer[blen++] = (byte) 0xE0; 343 buffer[blen++] = (byte) 0x00; 344 buffer[blen++] = (byte) 0x00; 345 } 346 } 347 348 351 private boolean canTruncate() { 352 if (typeName.equals(TypeId.CLOB_NAME)) { 354 return true; 355 } else if (typeName.equals(TypeId.VARCHAR_NAME)) { 356 return true; 357 } 358 return false; 359 } 360 361 364 private void truncate() 365 throws IOException { 366 int c = 0; 367 for (;;) { 368 c = reader.read(); 369 370 if (c < 0) { 371 break; 372 } else if (c != SPACE) { 373 throw new DerbyIOException( 374 MessageService.getTextMessage( 375 SQLState.LANG_STRING_TRUNCATION, 376 typeName, 377 "XXXX", 378 String.valueOf(valueLength)), 379 SQLState.LANG_STRING_TRUNCATION); 380 } 381 } 382 } 383 384 387 public void close() throws IOException 388 { 389 buffer = null; 394 } 395 396 401 public final int available() 402 { 403 int remainingBytes = reader.getLimit(); 404 return (BUFSIZE > remainingBytes ? remainingBytes : BUFSIZE); 410 } 411 } 412 413 | Popular Tags |