1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.nfc.tech; 18 19 import android.nfc.ErrorCodes; 20 import android.nfc.Tag; 21 import android.nfc.TagLostException; 22 import android.os.RemoteException; 23 import android.util.Log; 24 25 import java.io.IOException; 26 import java.nio.ByteBuffer; 27 import java.nio.ByteOrder; 28 29 /** 30 * Provides access to MIFARE Classic properties and I/O operations on a {@link Tag}. 31 * 32 * <p>Acquire a {@link MifareClassic} object using {@link #get}. 33 * 34 * <p>MIFARE Classic is also known as MIFARE Standard. 35 * <p>MIFARE Classic tags are divided into sectors, and each sector is sub-divided into 36 * blocks. Block size is always 16 bytes ({@link #BLOCK_SIZE}. Sector size varies. 37 * <ul> 38 * <li>MIFARE Classic Mini are 320 bytes ({@link #SIZE_MINI}), with 5 sectors each of 4 blocks. 39 * <li>MIFARE Classic 1k are 1024 bytes ({@link #SIZE_1K}), with 16 sectors each of 4 blocks. 40 * <li>MIFARE Classic 2k are 2048 bytes ({@link #SIZE_2K}), with 32 sectors each of 4 blocks. 41 * <li>MIFARE Classic 4k} are 4096 bytes ({@link #SIZE_4K}). The first 32 sectors contain 4 blocks 42 * and the last 8 sectors contain 16 blocks. 43 * </ul> 44 * 45 * <p>MIFARE Classic tags require authentication on a per-sector basis before any 46 * other I/O operations on that sector can be performed. There are two keys per sector, 47 * and ACL bits determine what I/O operations are allowed on that sector after 48 * authenticating with a key. {@see #authenticateSectorWithKeyA} and 49 * {@see #authenticateSectorWithKeyB}. 50 * 51 * <p>Three well-known authentication keys are defined in this class: 52 * {@link #KEY_DEFAULT}, {@link #KEY_MIFARE_APPLICATION_DIRECTORY}, 53 * {@link #KEY_NFC_FORUM}. 54 * <ul> 55 * <li>{@link #KEY_DEFAULT} is the default factory key for MIFARE Classic. 56 * <li>{@link #KEY_MIFARE_APPLICATION_DIRECTORY} is the well-known key for 57 * MIFARE Classic cards that have been formatted according to the 58 * MIFARE Application Directory (MAD) specification. 59 * <li>{@link #KEY_NFC_FORUM} is the well-known key for MIFARE Classic cards that 60 * have been formatted according to the NXP specification for NDEF on MIFARE Classic. 61 * 62 * <p>Implementation of this class on a Android NFC device is optional. 63 * If it is not implemented, then 64 * {@link MifareClassic} will never be enumerated in {@link Tag#getTechList}. 65 * If it is enumerated, then all {@link MifareClassic} I/O operations will be supported, 66 * and {@link Ndef#MIFARE_CLASSIC} NDEF tags will also be supported. In either case, 67 * {@link NfcA} will also be enumerated on the tag, because all MIFARE Classic tags are also 68 * {@link NfcA}. 69 * 70 * <p class="note"><strong>Note:</strong> Methods that perform I/O operations 71 * require the {@link android.Manifest.permission#NFC} permission. 72 */ 73 public final class MifareClassic extends BasicTagTechnology { 74 private static final String TAG = "NFC"; 75 76 /** 77 * The default factory key. 78 */ 79 public static final byte[] KEY_DEFAULT = 80 {(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF}; 81 /** 82 * The well-known key for tags formatted according to the 83 * MIFARE Application Directory (MAD) specification. 84 */ 85 public static final byte[] KEY_MIFARE_APPLICATION_DIRECTORY = 86 {(byte)0xA0,(byte)0xA1,(byte)0xA2,(byte)0xA3,(byte)0xA4,(byte)0xA5}; 87 /** 88 * The well-known key for tags formatted according to the 89 * NDEF on MIFARE Classic specification. 90 */ 91 public static final byte[] KEY_NFC_FORUM = 92 {(byte)0xD3,(byte)0xF7,(byte)0xD3,(byte)0xF7,(byte)0xD3,(byte)0xF7}; 93 94 /** A MIFARE Classic compatible card of unknown type */ 95 public static final int TYPE_UNKNOWN = -1; 96 /** A MIFARE Classic tag */ 97 public static final int TYPE_CLASSIC = 0; 98 /** A MIFARE Plus tag */ 99 public static final int TYPE_PLUS = 1; 100 /** A MIFARE Pro tag */ 101 public static final int TYPE_PRO = 2; 102 103 /** Tag contains 16 sectors, each with 4 blocks. */ 104 public static final int SIZE_1K = 1024; 105 /** Tag contains 32 sectors, each with 4 blocks. */ 106 public static final int SIZE_2K = 2048; 107 /** 108 * Tag contains 40 sectors. The first 32 sectors contain 4 blocks and the last 8 sectors 109 * contain 16 blocks. 110 */ 111 public static final int SIZE_4K = 4096; 112 /** Tag contains 5 sectors, each with 4 blocks. */ 113 public static final int SIZE_MINI = 320; 114 115 /** Size of a MIFARE Classic block (in bytes) */ 116 public static final int BLOCK_SIZE = 16; 117 118 private static final int MAX_BLOCK_COUNT = 256; 119 private static final int MAX_SECTOR_COUNT = 40; 120 121 private boolean mIsEmulated; 122 private int mType; 123 private int mSize; 124 125 /** 126 * Get an instance of {@link MifareClassic} for the given tag. 127 * <p>Does not cause any RF activity and does not block. 128 * <p>Returns null if {@link MifareClassic} was not enumerated in {@link Tag#getTechList}. 129 * This indicates the tag is not MIFARE Classic compatible, or this Android 130 * device does not support MIFARE Classic. 131 * 132 * @param tag an MIFARE Classic compatible tag 133 * @return MIFARE Classic object 134 */ get(Tag tag)135 public static MifareClassic get(Tag tag) { 136 if (!tag.hasTech(TagTechnology.MIFARE_CLASSIC)) return null; 137 try { 138 return new MifareClassic(tag); 139 } catch (RemoteException e) { 140 return null; 141 } 142 } 143 144 /** @hide */ MifareClassic(Tag tag)145 public MifareClassic(Tag tag) throws RemoteException { 146 super(tag, TagTechnology.MIFARE_CLASSIC); 147 148 NfcA a = NfcA.get(tag); // MIFARE Classic is always based on NFC a 149 150 mIsEmulated = false; 151 152 switch (a.getSak()) { 153 case 0x01: 154 case 0x08: 155 mType = TYPE_CLASSIC; 156 mSize = SIZE_1K; 157 break; 158 case 0x09: 159 mType = TYPE_CLASSIC; 160 mSize = SIZE_MINI; 161 break; 162 case 0x10: 163 mType = TYPE_PLUS; 164 mSize = SIZE_2K; 165 // SecLevel = SL2 166 break; 167 case 0x11: 168 mType = TYPE_PLUS; 169 mSize = SIZE_4K; 170 // Seclevel = SL2 171 break; 172 case 0x18: 173 mType = TYPE_CLASSIC; 174 mSize = SIZE_4K; 175 break; 176 case 0x28: 177 mType = TYPE_CLASSIC; 178 mSize = SIZE_1K; 179 mIsEmulated = true; 180 break; 181 case 0x38: 182 mType = TYPE_CLASSIC; 183 mSize = SIZE_4K; 184 mIsEmulated = true; 185 break; 186 case 0x88: 187 mType = TYPE_CLASSIC; 188 mSize = SIZE_1K; 189 // NXP-tag: false 190 break; 191 case 0x98: 192 case 0xB8: 193 mType = TYPE_PRO; 194 mSize = SIZE_4K; 195 break; 196 default: 197 // Stack incorrectly reported a MifareClassic. We cannot handle this 198 // gracefully - we have no idea of the memory layout. Bail. 199 throw new RuntimeException( 200 "Tag incorrectly enumerated as MIFARE Classic, SAK = " + a.getSak()); 201 } 202 } 203 204 /** 205 * Return the type of this MIFARE Classic compatible tag. 206 * <p>One of {@link #TYPE_UNKNOWN}, {@link #TYPE_CLASSIC}, {@link #TYPE_PLUS} or 207 * {@link #TYPE_PRO}. 208 * <p>Does not cause any RF activity and does not block. 209 * 210 * @return type 211 */ getType()212 public int getType() { 213 return mType; 214 } 215 216 /** 217 * Return the size of the tag in bytes 218 * <p>One of {@link #SIZE_MINI}, {@link #SIZE_1K}, {@link #SIZE_2K}, {@link #SIZE_4K}. 219 * These constants are equal to their respective size in bytes. 220 * <p>Does not cause any RF activity and does not block. 221 * @return size in bytes 222 */ getSize()223 public int getSize() { 224 return mSize; 225 } 226 227 /** 228 * Return true if the tag is emulated, determined at discovery time. 229 * These are actually smart-cards that emulate a MIFARE Classic interface. 230 * They can be treated identically to a MIFARE Classic tag. 231 * @hide 232 */ isEmulated()233 public boolean isEmulated() { 234 return mIsEmulated; 235 } 236 237 /** 238 * Return the number of MIFARE Classic sectors. 239 * <p>Does not cause any RF activity and does not block. 240 * @return number of sectors 241 */ getSectorCount()242 public int getSectorCount() { 243 switch (mSize) { 244 case SIZE_1K: 245 return 16; 246 case SIZE_2K: 247 return 32; 248 case SIZE_4K: 249 return 40; 250 case SIZE_MINI: 251 return 5; 252 default: 253 return 0; 254 } 255 } 256 257 /** 258 * Return the total number of MIFARE Classic blocks. 259 * <p>Does not cause any RF activity and does not block. 260 * @return total number of blocks 261 */ getBlockCount()262 public int getBlockCount() { 263 return mSize / BLOCK_SIZE; 264 } 265 266 /** 267 * Return the number of blocks in the given sector. 268 * <p>Does not cause any RF activity and does not block. 269 * 270 * @param sectorIndex index of sector, starting from 0 271 * @return number of blocks in the sector 272 */ getBlockCountInSector(int sectorIndex)273 public int getBlockCountInSector(int sectorIndex) { 274 validateSector(sectorIndex); 275 276 if (sectorIndex < 32) { 277 return 4; 278 } else { 279 return 16; 280 } 281 } 282 283 /** 284 * Return the sector that contains a given block. 285 * <p>Does not cause any RF activity and does not block. 286 * 287 * @param blockIndex index of block to lookup, starting from 0 288 * @return sector index that contains the block 289 */ blockToSector(int blockIndex)290 public int blockToSector(int blockIndex) { 291 validateBlock(blockIndex); 292 293 if (blockIndex < 32 * 4) { 294 return blockIndex / 4; 295 } else { 296 return 32 + (blockIndex - 32 * 4) / 16; 297 } 298 } 299 300 /** 301 * Return the first block of a given sector. 302 * <p>Does not cause any RF activity and does not block. 303 * 304 * @param sectorIndex index of sector to lookup, starting from 0 305 * @return block index of first block in sector 306 */ sectorToBlock(int sectorIndex)307 public int sectorToBlock(int sectorIndex) { 308 if (sectorIndex < 32) { 309 return sectorIndex * 4; 310 } else { 311 return 32 * 4 + (sectorIndex - 32) * 16; 312 } 313 } 314 315 /** 316 * Authenticate a sector with key A. 317 * 318 * <p>Successful authentication of a sector with key A enables other 319 * I/O operations on that sector. The set of operations granted by key A 320 * key depends on the ACL bits set in that sector. For more information 321 * see the MIFARE Classic specification on {@see http://www.nxp.com}. 322 * 323 * <p>A failed authentication attempt causes an implicit reconnection to the 324 * tag, so authentication to other sectors will be lost. 325 * 326 * <p>This is an I/O operation and will block until complete. It must 327 * not be called from the main application thread. A blocked call will be canceled with 328 * {@link IOException} if {@link #close} is called from another thread. 329 * 330 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 331 * 332 * @param sectorIndex index of sector to authenticate, starting from 0 333 * @param key 6-byte authentication key 334 * @return true on success, false on authentication failure 335 * @throws TagLostException if the tag leaves the field 336 * @throws IOException if there is an I/O failure, or the operation is canceled 337 */ authenticateSectorWithKeyA(int sectorIndex, byte[] key)338 public boolean authenticateSectorWithKeyA(int sectorIndex, byte[] key) throws IOException { 339 return authenticate(sectorIndex, key, true); 340 } 341 342 /** 343 * Authenticate a sector with key B. 344 * 345 * <p>Successful authentication of a sector with key B enables other 346 * I/O operations on that sector. The set of operations granted by key B 347 * depends on the ACL bits set in that sector. For more information 348 * see the MIFARE Classic specification on {@see http://www.nxp.com}. 349 * 350 * <p>A failed authentication attempt causes an implicit reconnection to the 351 * tag, so authentication to other sectors will be lost. 352 * 353 * <p>This is an I/O operation and will block until complete. It must 354 * not be called from the main application thread. A blocked call will be canceled with 355 * {@link IOException} if {@link #close} is called from another thread. 356 * 357 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 358 * 359 * @param sectorIndex index of sector to authenticate, starting from 0 360 * @param key 6-byte authentication key 361 * @return true on success, false on authentication failure 362 * @throws TagLostException if the tag leaves the field 363 * @throws IOException if there is an I/O failure, or the operation is canceled 364 */ authenticateSectorWithKeyB(int sectorIndex, byte[] key)365 public boolean authenticateSectorWithKeyB(int sectorIndex, byte[] key) throws IOException { 366 return authenticate(sectorIndex, key, false); 367 } 368 authenticate(int sector, byte[] key, boolean keyA)369 private boolean authenticate(int sector, byte[] key, boolean keyA) throws IOException { 370 validateSector(sector); 371 checkConnected(); 372 373 byte[] cmd = new byte[12]; 374 375 // First byte is the command 376 if (keyA) { 377 cmd[0] = 0x60; // phHal_eMifareAuthentA 378 } else { 379 cmd[0] = 0x61; // phHal_eMifareAuthentB 380 } 381 382 // Second byte is block address 383 // Authenticate command takes a block address. Authenticating a block 384 // of a sector will authenticate the entire sector. 385 cmd[1] = (byte) sectorToBlock(sector); 386 387 // Next 4 bytes are last 4 bytes of UID 388 byte[] uid = getTag().getId(); 389 System.arraycopy(uid, uid.length - 4, cmd, 2, 4); 390 391 // Next 6 bytes are key 392 System.arraycopy(key, 0, cmd, 6, 6); 393 394 try { 395 if (transceive(cmd, false) != null) { 396 return true; 397 } 398 } catch (TagLostException e) { 399 throw e; 400 } catch (IOException e) { 401 // No need to deal with, will return false anyway 402 } 403 return false; 404 } 405 406 /** 407 * Read 16-byte block. 408 * 409 * <p>This is an I/O operation and will block until complete. It must 410 * not be called from the main application thread. A blocked call will be canceled with 411 * {@link IOException} if {@link #close} is called from another thread. 412 * 413 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 414 * 415 * @param blockIndex index of block to read, starting from 0 416 * @return 16 byte block 417 * @throws TagLostException if the tag leaves the field 418 * @throws IOException if there is an I/O failure, or the operation is canceled 419 */ readBlock(int blockIndex)420 public byte[] readBlock(int blockIndex) throws IOException { 421 validateBlock(blockIndex); 422 checkConnected(); 423 424 byte[] cmd = { 0x30, (byte) blockIndex }; 425 return transceive(cmd, false); 426 } 427 428 /** 429 * Write 16-byte block. 430 * 431 * <p>This is an I/O operation and will block until complete. It must 432 * not be called from the main application thread. A blocked call will be canceled with 433 * {@link IOException} if {@link #close} is called from another thread. 434 * 435 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 436 * 437 * @param blockIndex index of block to write, starting from 0 438 * @param data 16 bytes of data to write 439 * @throws TagLostException if the tag leaves the field 440 * @throws IOException if there is an I/O failure, or the operation is canceled 441 */ writeBlock(int blockIndex, byte[] data)442 public void writeBlock(int blockIndex, byte[] data) throws IOException { 443 validateBlock(blockIndex); 444 checkConnected(); 445 if (data.length != 16) { 446 throw new IllegalArgumentException("must write 16-bytes"); 447 } 448 449 byte[] cmd = new byte[data.length + 2]; 450 cmd[0] = (byte) 0xA0; // MF write command 451 cmd[1] = (byte) blockIndex; 452 System.arraycopy(data, 0, cmd, 2, data.length); 453 454 transceive(cmd, false); 455 } 456 457 /** 458 * Increment a value block, storing the result in the temporary block on the tag. 459 * 460 * <p>This is an I/O operation and will block until complete. It must 461 * not be called from the main application thread. A blocked call will be canceled with 462 * {@link IOException} if {@link #close} is called from another thread. 463 * 464 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 465 * 466 * @param blockIndex index of block to increment, starting from 0 467 * @param value non-negative to increment by 468 * @throws TagLostException if the tag leaves the field 469 * @throws IOException if there is an I/O failure, or the operation is canceled 470 */ increment(int blockIndex, int value)471 public void increment(int blockIndex, int value) throws IOException { 472 validateBlock(blockIndex); 473 validateValueOperand(value); 474 checkConnected(); 475 476 ByteBuffer cmd = ByteBuffer.allocate(6); 477 cmd.order(ByteOrder.LITTLE_ENDIAN); 478 cmd.put( (byte) 0xC1 ); 479 cmd.put( (byte) blockIndex ); 480 cmd.putInt(value); 481 482 transceive(cmd.array(), false); 483 } 484 485 /** 486 * Decrement a value block, storing the result in the temporary block on the tag. 487 * 488 * <p>This is an I/O operation and will block until complete. It must 489 * not be called from the main application thread. A blocked call will be canceled with 490 * {@link IOException} if {@link #close} is called from another thread. 491 * 492 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 493 * 494 * @param blockIndex index of block to decrement, starting from 0 495 * @param value non-negative to decrement by 496 * @throws TagLostException if the tag leaves the field 497 * @throws IOException if there is an I/O failure, or the operation is canceled 498 */ decrement(int blockIndex, int value)499 public void decrement(int blockIndex, int value) throws IOException { 500 validateBlock(blockIndex); 501 validateValueOperand(value); 502 checkConnected(); 503 504 ByteBuffer cmd = ByteBuffer.allocate(6); 505 cmd.order(ByteOrder.LITTLE_ENDIAN); 506 cmd.put( (byte) 0xC0 ); 507 cmd.put( (byte) blockIndex ); 508 cmd.putInt(value); 509 510 transceive(cmd.array(), false); 511 } 512 513 /** 514 * Copy from the temporary block to a value block. 515 * 516 * <p>This is an I/O operation and will block until complete. It must 517 * not be called from the main application thread. A blocked call will be canceled with 518 * {@link IOException} if {@link #close} is called from another thread. 519 * 520 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 521 * 522 * @param blockIndex index of block to copy to 523 * @throws TagLostException if the tag leaves the field 524 * @throws IOException if there is an I/O failure, or the operation is canceled 525 */ transfer(int blockIndex)526 public void transfer(int blockIndex) throws IOException { 527 validateBlock(blockIndex); 528 checkConnected(); 529 530 byte[] cmd = { (byte) 0xB0, (byte) blockIndex }; 531 532 transceive(cmd, false); 533 } 534 535 /** 536 * Copy from a value block to the temporary block. 537 * 538 * <p>This is an I/O operation and will block until complete. It must 539 * not be called from the main application thread. A blocked call will be canceled with 540 * {@link IOException} if {@link #close} is called from another thread. 541 * 542 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 543 * 544 * @param blockIndex index of block to copy from 545 * @throws TagLostException if the tag leaves the field 546 * @throws IOException if there is an I/O failure, or the operation is canceled 547 */ restore(int blockIndex)548 public void restore(int blockIndex) throws IOException { 549 validateBlock(blockIndex); 550 checkConnected(); 551 552 byte[] cmd = { (byte) 0xC2, (byte) blockIndex }; 553 554 transceive(cmd, false); 555 } 556 557 /** 558 * Send raw NfcA data to a tag and receive the response. 559 * 560 * <p>This is equivalent to connecting to this tag via {@link NfcA} 561 * and calling {@link NfcA#transceive}. Note that all MIFARE Classic 562 * tags are based on {@link NfcA} technology. 563 * 564 * <p>Use {@link #getMaxTransceiveLength} to retrieve the maximum number of bytes 565 * that can be sent with {@link #transceive}. 566 * 567 * <p>This is an I/O operation and will block until complete. It must 568 * not be called from the main application thread. A blocked call will be canceled with 569 * {@link IOException} if {@link #close} is called from another thread. 570 * 571 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 572 * 573 * @see NfcA#transceive 574 */ transceive(byte[] data)575 public byte[] transceive(byte[] data) throws IOException { 576 return transceive(data, true); 577 } 578 579 /** 580 * Return the maximum number of bytes that can be sent with {@link #transceive}. 581 * @return the maximum number of bytes that can be sent with {@link #transceive}. 582 */ getMaxTransceiveLength()583 public int getMaxTransceiveLength() { 584 return getMaxTransceiveLengthInternal(); 585 } 586 587 /** 588 * Set the {@link #transceive} timeout in milliseconds. 589 * 590 * <p>The timeout only applies to {@link #transceive} on this object, 591 * and is reset to a default value when {@link #close} is called. 592 * 593 * <p>Setting a longer timeout may be useful when performing 594 * transactions that require a long processing time on the tag 595 * such as key generation. 596 * 597 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 598 * 599 * @param timeout timeout value in milliseconds 600 */ setTimeout(int timeout)601 public void setTimeout(int timeout) { 602 try { 603 int err = mTag.getTagService().setTimeout(TagTechnology.MIFARE_CLASSIC, timeout); 604 if (err != ErrorCodes.SUCCESS) { 605 throw new IllegalArgumentException("The supplied timeout is not valid"); 606 } 607 } catch (RemoteException e) { 608 Log.e(TAG, "NFC service dead", e); 609 } 610 } 611 612 /** 613 * Get the current {@link #transceive} timeout in milliseconds. 614 * 615 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 616 * 617 * @return timeout value in milliseconds 618 */ getTimeout()619 public int getTimeout() { 620 try { 621 return mTag.getTagService().getTimeout(TagTechnology.MIFARE_CLASSIC); 622 } catch (RemoteException e) { 623 Log.e(TAG, "NFC service dead", e); 624 return 0; 625 } 626 } 627 validateSector(int sector)628 private static void validateSector(int sector) { 629 // Do not be too strict on upper bounds checking, since some cards 630 // have more addressable memory than they report. For example, 631 // MIFARE Plus 2k cards will appear as MIFARE Classic 1k cards when in 632 // MIFARE Classic compatibility mode. 633 // Note that issuing a command to an out-of-bounds block is safe - the 634 // tag should report error causing IOException. This validation is a 635 // helper to guard against obvious programming mistakes. 636 if (sector < 0 || sector >= MAX_SECTOR_COUNT) { 637 throw new IndexOutOfBoundsException("sector out of bounds: " + sector); 638 } 639 } 640 validateBlock(int block)641 private static void validateBlock(int block) { 642 // Just looking for obvious out of bounds... 643 if (block < 0 || block >= MAX_BLOCK_COUNT) { 644 throw new IndexOutOfBoundsException("block out of bounds: " + block); 645 } 646 } 647 validateValueOperand(int value)648 private static void validateValueOperand(int value) { 649 if (value < 0) { 650 throw new IllegalArgumentException("value operand negative"); 651 } 652 } 653 } 654