private void grow(int newSize, boolean preserveData) throws IOException {

		int oldSize = this.size;
		this.size = newSize;

		// Currently using a single data buffer
		if (dataBufferIdTable.length == 1) {

			// Transition to an indexed chained buffer
			if (newSize > dataSpace) {

				DataBuffer firstBuffer = bufferMgr.getBuffer(firstBufferId);
				DataBuffer newFirstDataBuf = null;

				try {
					// Save data in new data buffer
					if (preserveData) {
						newFirstDataBuf = bufferMgr.createBuffer();
						newFirstDataBuf.copy(DATA_BASE_OFFSET_INDEXED, firstBuffer,
							DATA_BASE_OFFSET_NONINDEXED, oldSize);

						int indexedDataSpace = newFirstDataBuf.length() - DATA_BASE_OFFSET_INDEXED;
						byte[] zeroBytes = new byte[indexedDataSpace - oldSize];
						if (useXORMask) {
							int offset = oldSize;
							for (int i = 0; i < zeroBytes.length; i++, offset++) {
								zeroBytes[i] = xorMaskByte(offset, zeroBytes[i]);
							}
						}
						newFirstDataBuf.put(DATA_BASE_OFFSET_INDEXED + oldSize, zeroBytes);
					}

					// Establish index for DBBuffer
					createIndex(firstBuffer);
					firstBuffer = null;

					// Establish first data buffer
					if (preserveData) {
						addBuffer(0, newFirstDataBuf);
					}
				}
				finally {
					if (firstBuffer != null) {
						bufferMgr.releaseBuffer(firstBuffer);
					}
					if (newFirstDataBuf != null) {
						bufferMgr.releaseBuffer(newFirstDataBuf);
					}
				}

				return;
			}

			// Adjust stored buffer size
			DataBuffer buffer = bufferMgr.getBuffer(firstBufferId);
			buffer.putInt(DATA_LENGTH_OFFSET, getObfuscationDataLengthFieldValue());
			bufferMgr.releaseBuffer(buffer);
		}

		// Already using an index - existing data is always preserved
		else {
			byte[] emptyIndexData = new byte[indexesPerBuffer * ID_SIZE];
			Arrays.fill(emptyIndexData, (byte) 0xff);

			// Compute index counts
			int newIndexCount = ((newSize - 1) / dataSpace) + 1;
			int newIndexBufferCount = ((newIndexCount - 1) / indexesPerBuffer) + 1;

			// Grow dataBufferIdTable
			int[] newDataBufferIdTable = new int[newIndexCount];
			System.arraycopy(dataBufferIdTable, 0, newDataBufferIdTable, 0,
				dataBufferIdTable.length);
			Arrays.fill(newDataBufferIdTable, dataBufferIdTable.length, newIndexCount, -1);
			dataBufferIdTable = newDataBufferIdTable;

			// Grow indexBufferIdTable
			int oldIndexBufferCount = indexBufferIdTable.length;
			if (oldIndexBufferCount < newIndexBufferCount) {

				int[] newIndexBufferIdTable = new int[newIndexBufferCount];
				System.arraycopy(indexBufferIdTable, 0, newIndexBufferIdTable, 0,
					oldIndexBufferCount);
				Arrays.fill(newIndexBufferIdTable, oldIndexBufferCount, newIndexBufferCount, -1);
				indexBufferIdTable = newIndexBufferIdTable;

				// Allocate additional index buffers
				DataBuffer indexBuffer =
					bufferMgr.getBuffer(indexBufferIdTable[oldIndexBufferCount - 1]);
				for (int i = oldIndexBufferCount; i < newIndexBufferCount; i++) {
					indexBuffer = appendIndexBuffer(indexBuffer);
					indexBuffer.put(INDEX_BASE_OFFSET, emptyIndexData);  // initialize to all -1's
					indexBufferIdTable[i] = indexBuffer.getId();
				}
				bufferMgr.releaseBuffer(indexBuffer);
			}

			// Adjust stored buffer size
			DataBuffer buffer = bufferMgr.getBuffer(firstBufferId);
			buffer.putInt(DATA_LENGTH_OFFSET, getObfuscationDataLengthFieldValue());
			bufferMgr.releaseBuffer(buffer);
		}

	}
Increase the size of this DBBuffer object.
@param newSize new size.
@param preserveData if true, existing data is preserved at the original offsets.  If false,
no additional effort will be expended to preserve data.
@throws IOException thrown if an IO error occurs.
Ghidra/Framework/DB/src/main/java/db/ChainedBuffer.java