001// Copyright (c) FIRST and other WPILib contributors. 002// Open Source Software; you can modify and/or share it under the terms of 003// the WPILib BSD license file in the root directory of this project. 004 005package edu.wpi.first.util.struct; 006 007import java.nio.BufferUnderflowException; 008import java.nio.ByteBuffer; 009import java.nio.ByteOrder; 010import java.nio.ReadOnlyBufferException; 011import java.nio.charset.StandardCharsets; 012 013/** Dynamic (run-time) access to a serialized raw struct. */ 014public final class DynamicStruct { 015 private DynamicStruct(StructDescriptor desc, ByteBuffer data) { 016 m_desc = desc; 017 m_data = data.order(ByteOrder.LITTLE_ENDIAN); 018 } 019 020 /** 021 * Constructs a new dynamic struct object with internal storage. The descriptor must be valid. The 022 * internal storage is allocated using ByteBuffer.allocate(). 023 * 024 * @param desc struct descriptor 025 * @return dynamic struct object 026 * @throws IllegalStateException if struct descriptor is invalid 027 */ 028 public static DynamicStruct allocate(StructDescriptor desc) { 029 return new DynamicStruct(desc, ByteBuffer.allocate(desc.getSize())); 030 } 031 032 /** 033 * Constructs a new dynamic struct object with internal storage. The descriptor must be valid. The 034 * internal storage is allocated using ByteBuffer.allocateDirect(). 035 * 036 * @param desc struct descriptor 037 * @return dynamic struct object 038 * @throws IllegalStateException if struct descriptor is invalid 039 */ 040 public static DynamicStruct allocateDirect(StructDescriptor desc) { 041 return new DynamicStruct(desc, ByteBuffer.allocateDirect(desc.getSize())); 042 } 043 044 /** 045 * Constructs a new dynamic struct object. Note: the passed data buffer is not copied. 046 * Modifications to the passed buffer will be reflected in the struct and vice-versa. 047 * 048 * @param desc struct descriptor 049 * @param data byte buffer containing serialized data starting at current position 050 * @return dynamic struct object 051 */ 052 public static DynamicStruct wrap(StructDescriptor desc, ByteBuffer data) { 053 return new DynamicStruct(desc, data.slice()); 054 } 055 056 /** 057 * Gets the struct descriptor. 058 * 059 * @return struct descriptor 060 */ 061 public StructDescriptor getDescriptor() { 062 return m_desc; 063 } 064 065 /** 066 * Gets the serialized backing data buffer. 067 * 068 * @return data buffer 069 */ 070 public ByteBuffer getBuffer() { 071 return m_data.duplicate().position(0); 072 } 073 074 /** 075 * Overwrites the entire serialized struct by copying data from a byte array. 076 * 077 * @param data replacement data for the struct 078 * @throws BufferUnderflowException if data is smaller than the struct size 079 * @throws ReadOnlyBufferException if the underlying buffer is read-only 080 * @throws IllegalStateException if struct descriptor is invalid 081 */ 082 public void setData(byte[] data) { 083 if (data.length < m_desc.getSize()) { 084 throw new BufferUnderflowException(); 085 } 086 m_data.position(0).put(data); 087 } 088 089 /** 090 * Overwrites the entire serialized struct by copying data from a byte buffer. 091 * 092 * @param data replacement data for the struct; copy starts from current position 093 * @throws BufferUnderflowException if remaining data is smaller than the struct size 094 * @throws ReadOnlyBufferException if the underlying buffer is read-only 095 * @throws IllegalStateException if struct descriptor is invalid 096 */ 097 public void setData(ByteBuffer data) { 098 if (data.remaining() < m_desc.getSize()) { 099 throw new BufferUnderflowException(); 100 } 101 int oldLimit = data.limit(); 102 m_data.position(0).put(data.limit(m_desc.getSize())); 103 data.limit(oldLimit); 104 } 105 106 /** 107 * Gets a struct field descriptor by name. 108 * 109 * @param name field name 110 * @return field descriptor, or null if no field with that name exists 111 */ 112 public StructFieldDescriptor findField(String name) { 113 return m_desc.findFieldByName(name); 114 } 115 116 /** 117 * Gets the value of a boolean field. 118 * 119 * @param field field descriptor 120 * @param arrIndex array index (must be less than field array size) 121 * @return boolean field value 122 * @throws UnsupportedOperationException if field is not bool type 123 * @throws IllegalArgumentException if field is not a member of this struct 124 * @throws IllegalStateException if struct descriptor is invalid 125 * @throws ArrayIndexOutOfBoundsException if array index is out of bounds 126 */ 127 public boolean getBoolField(StructFieldDescriptor field, int arrIndex) { 128 if (field.getType() != StructFieldType.kBool) { 129 throw new UnsupportedOperationException("field is not bool type"); 130 } 131 return getFieldImpl(field, arrIndex) != 0; 132 } 133 134 /** 135 * Gets the value of a boolean field. 136 * 137 * @param field field descriptor 138 * @return boolean field value 139 * @throws UnsupportedOperationException if field is not bool type 140 * @throws IllegalArgumentException if field is not a member of this struct 141 * @throws IllegalStateException if struct descriptor is invalid 142 */ 143 public boolean getBoolField(StructFieldDescriptor field) { 144 return getBoolField(field, 0); 145 } 146 147 /** 148 * Sets the value of a boolean field. 149 * 150 * @param field field descriptor 151 * @param value boolean value 152 * @param arrIndex array index (must be less than field array size) 153 * @throws UnsupportedOperationException if field is not bool type 154 * @throws IllegalArgumentException if field is not a member of this struct 155 * @throws IllegalStateException if struct descriptor is invalid 156 * @throws ArrayIndexOutOfBoundsException if array index is out of bounds 157 * @throws ReadOnlyBufferException if the underlying buffer is read-only 158 */ 159 public void setBoolField(StructFieldDescriptor field, boolean value, int arrIndex) { 160 if (field.getType() != StructFieldType.kBool) { 161 throw new UnsupportedOperationException("field is not bool type"); 162 } 163 setFieldImpl(field, value ? 1 : 0, arrIndex); 164 } 165 166 /** 167 * Sets the value of a boolean field. 168 * 169 * @param field field descriptor 170 * @param value boolean value 171 * @throws UnsupportedOperationException if field is not bool type 172 * @throws IllegalArgumentException if field is not a member of this struct 173 * @throws IllegalStateException if struct descriptor is invalid 174 * @throws ReadOnlyBufferException if the underlying buffer is read-only 175 */ 176 public void setBoolField(StructFieldDescriptor field, boolean value) { 177 setBoolField(field, value, 0); 178 } 179 180 /** 181 * Gets the value of an integer field. 182 * 183 * @param field field descriptor 184 * @param arrIndex array index (must be less than field array size) 185 * @return integer field value 186 * @throws UnsupportedOperationException if field is not integer type 187 * @throws IllegalArgumentException if field is not a member of this struct 188 * @throws IllegalStateException if struct descriptor is invalid 189 * @throws ArrayIndexOutOfBoundsException if array index is out of bounds 190 */ 191 public long getIntField(StructFieldDescriptor field, int arrIndex) { 192 if (!field.isInt() && !field.isUint()) { 193 throw new UnsupportedOperationException("field is not integer type"); 194 } 195 return getFieldImpl(field, arrIndex); 196 } 197 198 /** 199 * Gets the value of an integer field. 200 * 201 * @param field field descriptor 202 * @return integer field value 203 * @throws UnsupportedOperationException if field is not integer type 204 * @throws IllegalArgumentException if field is not a member of this struct 205 * @throws IllegalStateException if struct descriptor is invalid 206 */ 207 public long getIntField(StructFieldDescriptor field) { 208 return getIntField(field, 0); 209 } 210 211 /** 212 * Sets the value of an integer field. 213 * 214 * @param field field descriptor 215 * @param value integer value 216 * @param arrIndex array index (must be less than field array size) 217 * @throws UnsupportedOperationException if field is not integer type 218 * @throws IllegalArgumentException if field is not a member of this struct 219 * @throws IllegalStateException if struct descriptor is invalid 220 * @throws ArrayIndexOutOfBoundsException if array index is out of bounds 221 * @throws ReadOnlyBufferException if the underlying buffer is read-only 222 */ 223 public void setIntField(StructFieldDescriptor field, long value, int arrIndex) { 224 if (!field.isInt() && !field.isUint()) { 225 throw new UnsupportedOperationException("field is not integer type"); 226 } 227 setFieldImpl(field, value, arrIndex); 228 } 229 230 /** 231 * Sets the value of an integer field. 232 * 233 * @param field field descriptor 234 * @param value integer value 235 * @throws UnsupportedOperationException if field is not integer type 236 * @throws IllegalArgumentException if field is not a member of this struct 237 * @throws IllegalStateException if struct descriptor is invalid 238 * @throws ReadOnlyBufferException if the underlying buffer is read-only 239 */ 240 public void setIntField(StructFieldDescriptor field, long value) { 241 setIntField(field, value, 0); 242 } 243 244 /** 245 * Gets the value of a float field. 246 * 247 * @param field field descriptor 248 * @param arrIndex array index (must be less than field array size) 249 * @return float field value 250 * @throws UnsupportedOperationException if field is not float type 251 * @throws IllegalArgumentException if field is not a member of this struct 252 * @throws IllegalStateException if struct descriptor is invalid 253 * @throws ArrayIndexOutOfBoundsException if array index is out of bounds 254 */ 255 public float getFloatField(StructFieldDescriptor field, int arrIndex) { 256 if (field.getType() != StructFieldType.kFloat) { 257 throw new UnsupportedOperationException("field is not float type"); 258 } 259 return Float.intBitsToFloat((int) getFieldImpl(field, arrIndex)); 260 } 261 262 /** 263 * Gets the value of a float field. 264 * 265 * @param field field descriptor 266 * @return float field value 267 * @throws UnsupportedOperationException if field is not float type 268 * @throws IllegalArgumentException if field is not a member of this struct 269 * @throws IllegalStateException if struct descriptor is invalid 270 */ 271 public float getFloatField(StructFieldDescriptor field) { 272 return getFloatField(field, 0); 273 } 274 275 /** 276 * Sets the value of a float field. 277 * 278 * @param field field descriptor 279 * @param value float value 280 * @param arrIndex array index (must be less than field array size) 281 * @throws UnsupportedOperationException if field is not float type 282 * @throws IllegalArgumentException if field is not a member of this struct 283 * @throws IllegalStateException if struct descriptor is invalid 284 * @throws ArrayIndexOutOfBoundsException if array index is out of bounds 285 * @throws ReadOnlyBufferException if the underlying buffer is read-only 286 */ 287 public void setFloatField(StructFieldDescriptor field, float value, int arrIndex) { 288 if (field.getType() != StructFieldType.kFloat) { 289 throw new UnsupportedOperationException("field is not float type"); 290 } 291 setFieldImpl(field, Float.floatToIntBits(value), arrIndex); 292 } 293 294 /** 295 * Sets the value of a float field. 296 * 297 * @param field field descriptor 298 * @param value float value 299 * @throws UnsupportedOperationException if field is not float type 300 * @throws IllegalArgumentException if field is not a member of this struct 301 * @throws IllegalStateException if struct descriptor is invalid 302 * @throws ReadOnlyBufferException if the underlying buffer is read-only 303 */ 304 public void setFloatField(StructFieldDescriptor field, float value) { 305 setFloatField(field, value, 0); 306 } 307 308 /** 309 * Gets the value of a double field. 310 * 311 * @param field field descriptor 312 * @param arrIndex array index (must be less than field array size) 313 * @return double field value 314 * @throws UnsupportedOperationException if field is not double type 315 * @throws IllegalArgumentException if field is not a member of this struct 316 * @throws IllegalStateException if struct descriptor is invalid 317 * @throws ArrayIndexOutOfBoundsException if array index is out of bounds 318 */ 319 public double getDoubleField(StructFieldDescriptor field, int arrIndex) { 320 if (field.getType() != StructFieldType.kDouble) { 321 throw new UnsupportedOperationException("field is not double type"); 322 } 323 return Double.longBitsToDouble(getFieldImpl(field, arrIndex)); 324 } 325 326 /** 327 * Gets the value of a double field. 328 * 329 * @param field field descriptor 330 * @return double field value 331 * @throws UnsupportedOperationException if field is not double type 332 * @throws IllegalArgumentException if field is not a member of this struct 333 * @throws IllegalStateException if struct descriptor is invalid 334 */ 335 public double getDoubleField(StructFieldDescriptor field) { 336 return getDoubleField(field, 0); 337 } 338 339 /** 340 * Sets the value of a double field. 341 * 342 * @param field field descriptor 343 * @param value double value 344 * @param arrIndex array index (must be less than field array size) 345 * @throws UnsupportedOperationException if field is not double type 346 * @throws IllegalArgumentException if field is not a member of this struct 347 * @throws IllegalStateException if struct descriptor is invalid 348 * @throws ArrayIndexOutOfBoundsException if array index is out of bounds 349 * @throws ReadOnlyBufferException if the underlying buffer is read-only 350 */ 351 public void setDoubleField(StructFieldDescriptor field, double value, int arrIndex) { 352 if (field.getType() != StructFieldType.kDouble) { 353 throw new UnsupportedOperationException("field is not double type"); 354 } 355 setFieldImpl(field, Double.doubleToLongBits(value), arrIndex); 356 } 357 358 /** 359 * Sets the value of a double field. 360 * 361 * @param field field descriptor 362 * @param value double value 363 * @throws UnsupportedOperationException if field is not double type 364 * @throws IllegalArgumentException if field is not a member of this struct 365 * @throws IllegalStateException if struct descriptor is invalid 366 * @throws ReadOnlyBufferException if the underlying buffer is read-only 367 */ 368 public void setDoubleField(StructFieldDescriptor field, double value) { 369 setDoubleField(field, value, 0); 370 } 371 372 /** 373 * Gets the value of a character or character array field. 374 * 375 * @param field field descriptor 376 * @return field value 377 * @throws UnsupportedOperationException if field is not char type 378 * @throws IllegalArgumentException if field is not a member of this struct 379 * @throws IllegalStateException if struct descriptor is invalid 380 */ 381 @SuppressWarnings({"PMD.CollapsibleIfStatements", "PMD.AvoidDeeplyNestedIfStmts"}) 382 public String getStringField(StructFieldDescriptor field) { 383 if (field.getType() != StructFieldType.kChar) { 384 throw new UnsupportedOperationException("field is not char type"); 385 } 386 if (!field.getParent().equals(m_desc)) { 387 throw new IllegalArgumentException("field is not part of this struct"); 388 } 389 if (!m_desc.isValid()) { 390 throw new IllegalStateException("struct descriptor is not valid"); 391 } 392 byte[] bytes = new byte[field.m_arraySize]; 393 m_data.position(field.m_offset).get(bytes, 0, field.m_arraySize); 394 // Find last non zero character 395 int stringLength = bytes.length; 396 for (; stringLength > 0; stringLength--) { 397 if (bytes[stringLength - 1] != 0) { 398 break; 399 } 400 } 401 // If string is all zeroes, its empty and return an empty string. 402 if (stringLength == 0) { 403 return ""; 404 } 405 // Check if the end of the string is in the middle of a continuation byte or 406 // not. 407 if ((bytes[stringLength - 1] & 0x80) != 0) { 408 // This is a UTF8 continuation byte. Make sure its valid. 409 // Walk back until initial byte is found 410 int utf8StartByte = stringLength; 411 for (; utf8StartByte > 0; utf8StartByte--) { 412 if ((bytes[utf8StartByte - 1] & 0x40) != 0) { 413 // Having 2nd bit set means start byte 414 break; 415 } 416 } 417 if (utf8StartByte == 0) { 418 // This case means string only contains continuation bytes 419 return ""; 420 } 421 utf8StartByte--; 422 // Check if its a 2, 3, or 4 byte 423 byte checkByte = bytes[utf8StartByte]; 424 if ((checkByte & 0xE0) == 0xC0) { 425 // 2 byte, need 1 more byte 426 if (utf8StartByte != stringLength - 2) { 427 stringLength = utf8StartByte; 428 } 429 } else if ((checkByte & 0xF0) == 0xE0) { 430 // 3 byte, need 2 more bytes 431 if (utf8StartByte != stringLength - 3) { 432 stringLength = utf8StartByte; 433 } 434 } else if ((checkByte & 0xF8) == 0xF0) { 435 // 4 byte, need 3 more bytes 436 if (utf8StartByte != stringLength - 4) { 437 stringLength = utf8StartByte; 438 } 439 } 440 // If we get here, the string is either completely garbage or fine. 441 } 442 443 return new String(bytes, 0, stringLength, StandardCharsets.UTF_8); 444 } 445 446 /** 447 * Sets the value of a character or character array field. 448 * 449 * @param field field descriptor 450 * @param value field value 451 * @return true if the full value fit in the struct, false if truncated 452 * @throws UnsupportedOperationException if field is not char type 453 * @throws IllegalArgumentException if field is not a member of this struct 454 * @throws IllegalStateException if struct descriptor is invalid 455 */ 456 public boolean setStringField(StructFieldDescriptor field, String value) { 457 if (field.getType() != StructFieldType.kChar) { 458 throw new UnsupportedOperationException("field is not char type"); 459 } 460 if (!field.getParent().equals(m_desc)) { 461 throw new IllegalArgumentException("field is not part of this struct"); 462 } 463 if (!m_desc.isValid()) { 464 throw new IllegalStateException("struct descriptor is not valid"); 465 } 466 ByteBuffer bb = StandardCharsets.UTF_8.encode(value); 467 int len = Math.min(bb.remaining(), field.m_arraySize); 468 boolean copiedFull = len == bb.remaining(); 469 m_data.position(field.m_offset).put(bb.limit(len)); 470 for (int i = len; i < field.m_arraySize; i++) { 471 m_data.put((byte) 0); 472 } 473 return copiedFull; 474 } 475 476 /** 477 * Gets the value of a struct field. 478 * 479 * @param field field descriptor 480 * @param arrIndex array index (must be less than field array size) 481 * @return field value 482 * @throws UnsupportedOperationException if field is not of struct type 483 * @throws IllegalArgumentException if field is not a member of this struct 484 * @throws IllegalStateException if struct descriptor is invalid 485 * @throws ArrayIndexOutOfBoundsException if array index is out of bounds 486 */ 487 public DynamicStruct getStructField(StructFieldDescriptor field, int arrIndex) { 488 if (field.getType() != StructFieldType.kStruct) { 489 throw new UnsupportedOperationException("field is not struct type"); 490 } 491 if (!field.getParent().equals(m_desc)) { 492 throw new IllegalArgumentException("field is not part of this struct"); 493 } 494 if (!m_desc.isValid()) { 495 throw new IllegalStateException("struct descriptor is not valid"); 496 } 497 if (arrIndex < 0 || arrIndex >= field.m_arraySize) { 498 throw new ArrayIndexOutOfBoundsException( 499 "arrIndex (" + arrIndex + ") is larger than array size (" + field.m_arraySize + ")"); 500 } 501 StructDescriptor struct = field.getStruct(); 502 return wrap(struct, m_data.position(field.m_offset + arrIndex * struct.m_size)); 503 } 504 505 /** 506 * Gets the value of a struct field. 507 * 508 * @param field field descriptor 509 * @return field value 510 * @throws UnsupportedOperationException if field is not of struct type 511 * @throws IllegalArgumentException if field is not a member of this struct 512 * @throws IllegalStateException if struct descriptor is invalid 513 */ 514 public DynamicStruct getStructField(StructFieldDescriptor field) { 515 return getStructField(field, 0); 516 } 517 518 /** 519 * Sets the value of a struct field. 520 * 521 * @param field field descriptor 522 * @param value struct value 523 * @param arrIndex array index (must be less than field array size) 524 * @throws UnsupportedOperationException if field is not struct type 525 * @throws IllegalArgumentException if field is not a member of this struct 526 * @throws IllegalStateException if struct descriptor is invalid 527 * @throws ArrayIndexOutOfBoundsException if array index is out of bounds 528 * @throws ReadOnlyBufferException if the underlying buffer is read-only 529 */ 530 public void setStructField(StructFieldDescriptor field, DynamicStruct value, int arrIndex) { 531 if (field.getType() != StructFieldType.kStruct) { 532 throw new UnsupportedOperationException("field is not struct type"); 533 } 534 if (!field.getParent().equals(m_desc)) { 535 throw new IllegalArgumentException("field is not part of this struct"); 536 } 537 if (!m_desc.isValid()) { 538 throw new IllegalStateException("struct descriptor is not valid"); 539 } 540 StructDescriptor struct = field.getStruct(); 541 if (!value.getDescriptor().equals(struct)) { 542 throw new IllegalArgumentException("value's struct type does not match field struct type"); 543 } 544 if (!value.getDescriptor().isValid()) { 545 throw new IllegalStateException("value's struct descriptor is not valid"); 546 } 547 if (arrIndex < 0 || arrIndex >= field.m_arraySize) { 548 throw new ArrayIndexOutOfBoundsException( 549 "arrIndex (" + arrIndex + ") is larger than array size (" + field.m_arraySize + ")"); 550 } 551 m_data 552 .position(field.m_offset + arrIndex * struct.m_size) 553 .put(value.m_data.position(0).limit(value.getDescriptor().getSize())); 554 } 555 556 /** 557 * Sets the value of a struct field. 558 * 559 * @param field field descriptor 560 * @param value struct value 561 * @throws UnsupportedOperationException if field is not struct type 562 * @throws IllegalArgumentException if field is not a member of this struct 563 * @throws IllegalStateException if struct descriptor is invalid 564 * @throws ReadOnlyBufferException if the underlying buffer is read-only 565 */ 566 public void setStructField(StructFieldDescriptor field, DynamicStruct value) { 567 setStructField(field, value, 0); 568 } 569 570 private long getFieldImpl(StructFieldDescriptor field, int arrIndex) { 571 if (!field.getParent().equals(m_desc)) { 572 throw new IllegalArgumentException("field is not part of this struct"); 573 } 574 if (!m_desc.isValid()) { 575 throw new IllegalStateException("struct descriptor is not valid"); 576 } 577 if (arrIndex < 0 || arrIndex >= field.m_arraySize) { 578 throw new ArrayIndexOutOfBoundsException( 579 "arrIndex (" + arrIndex + ") is larger than array size (" + field.m_arraySize + ")"); 580 } 581 582 long val; 583 switch (field.m_size) { 584 case 1: 585 val = m_data.get(field.m_offset + arrIndex); 586 break; 587 case 2: 588 val = m_data.getShort(field.m_offset + arrIndex * 2); 589 break; 590 case 4: 591 val = m_data.getInt(field.m_offset + arrIndex * 4); 592 break; 593 case 8: 594 val = m_data.getLong(field.m_offset + arrIndex * 8); 595 break; 596 default: 597 throw new IllegalStateException("invalid field size"); 598 } 599 600 if (field.isUint() || field.getType() == StructFieldType.kBool) { 601 // for unsigned fields, we can simply logical shift and mask 602 return (val >>> field.m_bitShift) & field.getBitMask(); 603 } else { 604 // to get sign extension, shift so the sign bit within the bitfield goes to the long's sign 605 // bit (also clearing all higher bits), then shift back down (also clearing all lower bits); 606 // since upper and lower bits are cleared with the shifts, the bitmask is unnecessary 607 return (val << (64 - field.m_bitShift - field.getBitWidth())) >> (64 - field.getBitWidth()); 608 } 609 } 610 611 private void setFieldImpl(StructFieldDescriptor field, long value, int arrIndex) { 612 if (!field.getParent().equals(m_desc)) { 613 throw new IllegalArgumentException("field is not part of this struct"); 614 } 615 if (!m_desc.isValid()) { 616 throw new IllegalStateException("struct descriptor is not valid"); 617 } 618 if (arrIndex < 0 || arrIndex >= field.m_arraySize) { 619 throw new ArrayIndexOutOfBoundsException( 620 "arrIndex (" + arrIndex + ") is larger than array size (" + field.m_arraySize + ")"); 621 } 622 623 // common case is no bit shift and no masking 624 if (!field.isBitField()) { 625 switch (field.m_size) { 626 case 1: 627 m_data.put(field.m_offset + arrIndex, (byte) value); 628 break; 629 case 2: 630 m_data.putShort(field.m_offset + arrIndex * 2, (short) value); 631 break; 632 case 4: 633 m_data.putInt(field.m_offset + arrIndex * 4, (int) value); 634 break; 635 case 8: 636 m_data.putLong(field.m_offset + arrIndex * 8, value); 637 break; 638 default: 639 throw new IllegalStateException("invalid field size"); 640 } 641 return; 642 } 643 644 // handle bit shifting and masking into current value 645 switch (field.m_size) { 646 case 1: 647 { 648 byte val = m_data.get(field.m_offset + arrIndex); 649 val &= (byte) ~(field.getBitMask() << field.m_bitShift); 650 val |= (byte) ((value & field.getBitMask()) << field.m_bitShift); 651 m_data.put(field.m_offset + arrIndex, val); 652 break; 653 } 654 case 2: 655 { 656 short val = m_data.getShort(field.m_offset + arrIndex * 2); 657 val &= (short) ~(field.getBitMask() << field.m_bitShift); 658 val |= (short) ((value & field.getBitMask()) << field.m_bitShift); 659 m_data.putShort(field.m_offset + arrIndex * 2, val); 660 break; 661 } 662 case 4: 663 { 664 int val = m_data.getInt(field.m_offset + arrIndex * 4); 665 val &= (int) ~(field.getBitMask() << field.m_bitShift); 666 val |= (int) ((value & field.getBitMask()) << field.m_bitShift); 667 m_data.putInt(field.m_offset + arrIndex * 4, val); 668 break; 669 } 670 case 8: 671 { 672 long val = m_data.getLong(field.m_offset + arrIndex * 8); 673 val &= ~(field.getBitMask() << field.m_bitShift); 674 val |= (value & field.getBitMask()) << field.m_bitShift; 675 m_data.putLong(field.m_offset + arrIndex * 8, val); 676 break; 677 } 678 default: 679 throw new IllegalStateException("invalid field size"); 680 } 681 } 682 683 private final StructDescriptor m_desc; 684 private final ByteBuffer m_data; 685}