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