@Override
	public DataTypeComponent insertBitFieldAt(int byteOffset, int byteWidth, int bitOffset,
			DataType baseDataType, int bitSize, String componentName, String comment)
			throws InvalidDataTypeException {
		lock.acquire();
		try {
			checkDeleted();
			BitFieldDataType.checkBaseDataType(baseDataType);
			baseDataType = baseDataType.clone(dataMgr);

			if (byteOffset < 0 || bitSize < 0) {
				throw new IllegalArgumentException(
					"Negative values not permitted when defining bitfield");
			}
			if (byteWidth <= 0) {
				throw new IllegalArgumentException("Invalid byteWidth");
			}

			int effectiveBitSize =
				BitFieldDataType.getEffectiveBitSize(bitSize, baseDataType.getLength());

			int minByteWidth = BitFieldDataType.getMinimumStorageSize(effectiveBitSize + bitOffset);
			if (byteWidth < minByteWidth) {
				throw new IllegalArgumentException(
					"Bitfield does not fit within specified constraints");
			}

			boolean bigEndian = getDataOrganization().isBigEndian();

			boolean hasConflict = false;
			int additionalShift = 0;

			int startBitOffset = BitOffsetComparator.getNormalizedBitfieldOffset(byteOffset,
				byteWidth, effectiveBitSize, bitOffset, bigEndian);

			Comparator<Object> bitOffsetComparator =
				bigEndian ? BitOffsetComparator.INSTANCE_BE : BitOffsetComparator.INSTANCE_LE;
			int startIndex = Collections.binarySearch(components, Integer.valueOf(startBitOffset),
				bitOffsetComparator);
			if (startIndex < 0) {
				startIndex = -startIndex - 1;
			}
			else {
				hasConflict = true;
				DataTypeComponentDB dtc = components.get(startIndex);
				if (bitSize == 0 || dtc.isZeroBitFieldComponent()) {
					hasConflict = dtc.getOffset() != (startBitOffset / 8);
				}
				if (hasConflict) {
					additionalShift = byteOffset - dtc.getOffset();
				}
			}

			int ordinal; // computed ordinal will be adjusted after insertion complete
			if (startIndex < components.size()) {
				DataTypeComponentDB dtc = components.get(startIndex);
				ordinal = dtc.getOrdinal();
			}
			else {
				ordinal = startIndex;
			}

			if (isPackingEnabled()) {
				insertBitField(ordinal, 0, 0, baseDataType, effectiveBitSize, componentName,
					comment);
			}

			int endIndex = startIndex;
			if (startIndex < components.size()) {
				// some shifting of components may be required
				int endBitOffset = startBitOffset;
				if (effectiveBitSize != 0) {
					endBitOffset += effectiveBitSize - 1;
				}
				endIndex = Collections.binarySearch(components, Integer.valueOf(endBitOffset),
					bitOffsetComparator);
				if (endIndex < 0) {
					endIndex = -endIndex - 1;
				}
				else if (effectiveBitSize != 0) {
					hasConflict = true;
				}
			}

			if (startIndex != endIndex) {
				hasConflict = true;
			}

			// Any conflict will force a full insertion of byteWidth
			if (hasConflict) {
				shiftOffsets(startIndex, 1, byteWidth + additionalShift);
			}

			int requiredLength = byteOffset + byteWidth;
			if (requiredLength > structLength) {
				structLength = requiredLength;
			}

			// adjust for minimal storage use
			int storageBitOffset = bitOffset % 8;
			int revisedOffset;
			if (bigEndian) {
				revisedOffset = byteOffset + byteWidth - ((effectiveBitSize + bitOffset + 7) / 8);
			}
			else {
				revisedOffset = byteOffset + (bitOffset / 8);
			}

			BitFieldDataType bitfieldDt =
				new BitFieldDBDataType(baseDataType, bitSize, storageBitOffset);

			DBRecord rec = componentAdapter.createRecord(dataMgr.getResolvedID(bitfieldDt), key,
				bitfieldDt.getStorageSize(), ordinal, revisedOffset, componentName, comment);
			DataTypeComponentDB dtc = new DataTypeComponentDB(dataMgr, componentAdapter, this, rec);
			bitfieldDt.addParent(this); // has no affect
			components.add(startIndex, dtc);

			adjustNonPackedComponents(true);
			notifySizeChanged(false);
			return dtc;
		}
		catch (IOException e) {
			dataMgr.dbError(e);
		}
		finally {
			lock.release();
		}
		return null;
	}
Eliminate use of old trailing flex-array specification which is now specified using a
zero-element array.  Due to the specification of a new array datatype this must handle two
cases when an old flex-array component is exists:
<ol>
<li>read-only case: associated {@link DataTypeManagerDB} is not updatable.  This is the
normal case for an open archive.  A non-DB ArrayDataType must be employed with an immutable
{@link DataTypeProxyComponentDB} in place of the flex-array component.</li>
<li>upgrade (open for update with open transaction): the flex-array record is modified to
indicate an appropriate resolved zero-element array.
</ol>
<p>
NOTE: When {@link DataTypeManagerDB} is instantiated for update an upgrade must be forced
based upon the {@link CompositeDBAdapter#isFlexArrayMigrationRequired()} indicator.  The
upgrade logic(see
{@link DataTypeManagerDB#migrateOldFlexArrayComponentsIfRequired(TaskMonitor)}) instantiates
all structures within the databases with an open transaction allowing this method to perform
the necessary flex-array record migration.
<p>
NOTE: The offset of the migrated flex array component and structure length may change during
upgrade when packing is enabled when the original packed structure length did not properly
factor the flex-array alignment.  Repack does not occur in the read-only case.

@param oldFlexArrayRecord record which corresponds to an old flex-array component
@throws IOException if a database error occurs
Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java