Bug 575413: Accommodate addressableSize != 1 in HexIntegerRendering

Change-Id: I9b1e9e502ffc40315f971e1444b1c97d612399ac
Signed-off-by: John Dallaway <john@dallaway.org.uk>
Reviewed-on: https://git.eclipse.org/r/c/platform/eclipse.platform.debug/+/184023
Tested-by: Platform Bot <platform-bot@eclipse.org>
Reviewed-by: Sarika Sinha <sarika.sinha@in.ibm.com>
diff --git a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/AutomatedSuite.java b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/AutomatedSuite.java
index 5476f0d..3692256 100644
--- a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/AutomatedSuite.java
+++ b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/AutomatedSuite.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2020 IBM Corporation and others.
+ * Copyright (c) 2009, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -45,6 +45,7 @@
 import org.eclipse.debug.tests.statushandlers.StatusHandlerTests;
 import org.eclipse.debug.tests.stepfilters.StepFiltersTests;
 import org.eclipse.debug.tests.view.memory.MemoryRenderingTests;
+import org.eclipse.debug.tests.view.memory.TableRenderingTests;
 import org.eclipse.debug.tests.viewer.model.ChildrenUpdateTests;
 import org.eclipse.debug.tests.viewer.model.FilterTransformTests;
 import org.eclipse.debug.tests.viewer.model.PresentationContextTests;
@@ -91,6 +92,7 @@
 
 		// Memory view
 		MemoryRenderingTests.class,
+		TableRenderingTests.class,
 
 		// Launch framework
 		LaunchConfigurationTests.class,
diff --git a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/view/memory/TableRenderingTests.java b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/view/memory/TableRenderingTests.java
new file mode 100644
index 0000000..9fda86d
--- /dev/null
+++ b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/view/memory/TableRenderingTests.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ *  Copyright (c) 2021 John Dallaway and others.
+ *
+ *  This program and the accompanying materials
+ *  are made available under the terms of the Eclipse Public License 2.0
+ *  which accompanies this distribution, and is available at
+ *  https://www.eclipse.org/legal/epl-2.0/
+ *
+ *  SPDX-License-Identifier: EPL-2.0
+ *
+ *  Contributors:
+ *     John Dallaway - initial implementation
+ *******************************************************************************/
+package org.eclipse.debug.tests.view.memory;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import java.math.BigInteger;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.model.IMemoryBlockExtension;
+import org.eclipse.debug.core.model.MemoryByte;
+import org.eclipse.debug.internal.ui.views.memory.renderings.AbstractIntegerRendering;
+import org.eclipse.debug.internal.ui.views.memory.renderings.HexIntegerRendering;
+import org.eclipse.debug.internal.ui.views.memory.renderings.RenderingsUtil;
+import org.junit.Test;
+
+/**
+ * Tests for translation of memory bytes between in-memory representation and UI
+ * presentation
+ */
+@SuppressWarnings("restriction")
+public class TableRenderingTests {
+
+	private static final byte[] TWO_BYTES = new byte[] {
+			(byte) 0x67, (byte) 0x89 };
+	private static final byte[] FOUR_BYTES = new byte[] {
+			(byte) 0x45, (byte) 0x67, (byte) 0x89, (byte) 0xab };
+	private static final byte[] EIGHT_BYTES = new byte[] {
+			(byte) 0x01, (byte) 0x23, (byte) 0x45, (byte) 0x67, (byte) 0x89,
+			(byte) 0xab, (byte) 0xcd, (byte) 0xef };
+
+	@Test
+	public void testHexIntegerRendering() throws DebugException {
+		testIntegerRendering(createHexIntegerRendering(1), TWO_BYTES, "6789", "8967"); //$NON-NLS-1$ //$NON-NLS-2$
+		testIntegerRendering(createHexIntegerRendering(2), TWO_BYTES, "6789", "6789"); //$NON-NLS-1$ //$NON-NLS-2$
+		testIntegerRendering(createHexIntegerRendering(1), FOUR_BYTES, "456789AB", "AB896745"); //$NON-NLS-1$ //$NON-NLS-2$
+		testIntegerRendering(createHexIntegerRendering(2), FOUR_BYTES, "456789AB", "89AB4567"); //$NON-NLS-1$ //$NON-NLS-2$
+		testIntegerRendering(createHexIntegerRendering(4), FOUR_BYTES, "456789AB", "456789AB"); //$NON-NLS-1$ //$NON-NLS-2$
+		testIntegerRendering(createHexIntegerRendering(1), EIGHT_BYTES, "0123456789ABCDEF", "EFCDAB8967452301"); //$NON-NLS-1$ //$NON-NLS-2$
+		testIntegerRendering(createHexIntegerRendering(2), EIGHT_BYTES, "0123456789ABCDEF", "CDEF89AB45670123"); //$NON-NLS-1$ //$NON-NLS-2$
+		testIntegerRendering(createHexIntegerRendering(4), EIGHT_BYTES, "0123456789ABCDEF", "89ABCDEF01234567"); //$NON-NLS-1$ //$NON-NLS-2$
+		testIntegerRendering(createHexIntegerRendering(8), EIGHT_BYTES, "0123456789ABCDEF", "0123456789ABCDEF"); //$NON-NLS-1$ //$NON-NLS-2$
+	}
+
+	private void testIntegerRendering(AbstractIntegerRendering rendering, byte[] bytes, String bigEndianString, String littleEndianString) throws DebugException {
+		final IMemoryBlockExtension block = new TableRenderingTestsMemoryBlock(bytes, rendering.getAddressableSize());
+		rendering.init(null, block);
+		final MemoryByte[] memoryBytes = block.getBytesFromOffset(BigInteger.ZERO, bytes.length / rendering.getAddressableSize());
+
+		rendering.setDisplayEndianess(RenderingsUtil.BIG_ENDIAN);
+		assertEquals(bigEndianString, rendering.getString(null, null, memoryBytes));
+		assertArrayEquals(bytes, rendering.getBytes(null, null, memoryBytes, bigEndianString));
+
+		rendering.setDisplayEndianess(RenderingsUtil.LITTLE_ENDIAN);
+		assertEquals(littleEndianString, rendering.getString(null, null, memoryBytes));
+		assertArrayEquals(bytes, rendering.getBytes(null, null, memoryBytes, littleEndianString));
+	}
+
+	private HexIntegerRendering createHexIntegerRendering(int addressableSize) {
+		return new HexIntegerRendering(null) {
+			@Override
+			public int getAddressableSize() {
+				return addressableSize;
+			}
+		};
+	}
+
+}
diff --git a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/view/memory/TableRenderingTestsMemoryBlock.java b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/view/memory/TableRenderingTestsMemoryBlock.java
new file mode 100644
index 0000000..28b125b
--- /dev/null
+++ b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/view/memory/TableRenderingTestsMemoryBlock.java
@@ -0,0 +1,173 @@
+/*******************************************************************************
+ *  Copyright (c) 2021 John Dallaway and others.
+ *
+ *  This program and the accompanying materials
+ *  are made available under the terms of the Eclipse Public License 2.0
+ *  which accompanies this distribution, and is available at
+ *  https://www.eclipse.org/legal/epl-2.0/
+ *
+ *  SPDX-License-Identifier: EPL-2.0
+ *
+ *  Contributors:
+ *     John Dallaway - initial implementation
+ *******************************************************************************/
+package org.eclipse.debug.tests.view.memory;
+
+import java.math.BigInteger;
+
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.model.IDebugTarget;
+import org.eclipse.debug.core.model.IMemoryBlockExtension;
+import org.eclipse.debug.core.model.IMemoryBlockRetrieval;
+import org.eclipse.debug.core.model.MemoryByte;
+
+/**
+ * Minimal memory block implementation for use with
+ * {@link org.eclipse.debug.tests.view.memory.TableRenderingTests} only
+ */
+public class TableRenderingTestsMemoryBlock implements IMemoryBlockExtension {
+
+	private int fAddressableSize;
+	private byte[] fBytes;
+
+	public TableRenderingTestsMemoryBlock(byte[] bytes, int addressableSize) {
+		fBytes = bytes;
+		fAddressableSize = addressableSize;
+	}
+
+	@Override
+	public long getStartAddress() {
+		return 0;
+	}
+
+	@Override
+	public long getLength() {
+		return fBytes.length;
+	}
+
+	@Override
+	public byte[] getBytes() throws DebugException {
+		return fBytes;
+	}
+
+	@Override
+	public boolean supportsValueModification() {
+		return false;
+	}
+
+	@Override
+	public void setValue(long offset, byte[] bytes) throws DebugException {
+	}
+
+	@Override
+	public String getModelIdentifier() {
+		return null;
+	}
+
+	@Override
+	public IDebugTarget getDebugTarget() {
+		return null;
+	}
+
+	@Override
+	public ILaunch getLaunch() {
+		return null;
+	}
+
+	@Override
+	public <T> T getAdapter(Class<T> adapter) {
+		return null;
+	}
+
+	@Override
+	public String getExpression() {
+		return null;
+	}
+
+	@Override
+	public BigInteger getBigBaseAddress() throws DebugException {
+		return null;
+	}
+
+	@Override
+	public BigInteger getMemoryBlockStartAddress() throws DebugException {
+		return null;
+	}
+
+	@Override
+	public BigInteger getMemoryBlockEndAddress() throws DebugException {
+		return null;
+	}
+
+	@Override
+	public BigInteger getBigLength() throws DebugException {
+		return null;
+	}
+
+	@Override
+	public int getAddressSize() throws DebugException {
+		return 0;
+	}
+
+	@Override
+	public boolean supportBaseAddressModification() throws DebugException {
+		return false;
+	}
+
+	@Override
+	public boolean supportsChangeManagement() {
+		return false;
+	}
+
+	@Override
+	public void setBaseAddress(BigInteger address) throws DebugException {
+	}
+
+	@Override
+	public MemoryByte[] getBytesFromOffset(BigInteger unitOffset, long addressableUnits) throws DebugException {
+		assert BigInteger.ZERO.equals(unitOffset);
+		final MemoryByte[] memoryBytes = new MemoryByte[(int) (addressableUnits * getAddressableSize())];
+		for (int n = 0; n < memoryBytes.length; n++) {
+			memoryBytes[n] = new MemoryByte(fBytes[n]);
+		}
+		return memoryBytes;
+	}
+
+	@Override
+	public MemoryByte[] getBytesFromAddress(BigInteger address, long units) throws DebugException {
+		return null;
+	}
+
+	@Override
+	public void setValue(BigInteger offset, byte[] bytes) throws DebugException {
+	}
+
+	@Override
+	public void connect(Object client) {
+	}
+
+	@Override
+	public void disconnect(Object client) {
+	}
+
+	@Override
+	public Object[] getConnections() {
+		return null;
+	}
+
+	@Override
+	public void dispose() throws DebugException {
+	}
+
+	@Override
+	public IMemoryBlockRetrieval getMemoryBlockRetrieval() {
+		return null;
+	}
+
+	@Override
+	public int getAddressableSize() throws DebugException {
+		return fAddressableSize;
+	}
+
+}
diff --git a/org.eclipse.debug.ui/META-INF/MANIFEST.MF b/org.eclipse.debug.ui/META-INF/MANIFEST.MF
index 8103692..58f5944 100644
--- a/org.eclipse.debug.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.debug.ui/META-INF/MANIFEST.MF
@@ -49,6 +49,7 @@
  org.eclipse.debug.internal.ui.viewers.model;x-friends:="org.eclipse.debug.tests,org.eclipse.jdt.debug.tests,org.eclipse.debug.examples.ui",
  org.eclipse.debug.internal.ui.viewers.model.provisional;
   x-friends:="org.eclipse.cdt.dsf.gdb.ui,
+ org.eclipse.debug.internal.ui.views.memory.renderings;x-internal:=true,
    org.eclipse.cdt.dsf.ui,
    org.eclipse.debug.examples.ui,
    org.eclipse.debug.tests,
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/memory/renderings/HexIntegerRendering.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/memory/renderings/HexIntegerRendering.java
index 4e05c22..05b5896 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/memory/renderings/HexIntegerRendering.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/memory/renderings/HexIntegerRendering.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007 IBM Corporation and others.
+ * Copyright (c) 2007, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -11,6 +11,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     David Pickens - [Memory View] Endian in hex view and ASCII view doesn't work
+ *     John Dallaway - Accommodate addressableSize != 1 (bug 575413)
  *******************************************************************************/
 package org.eclipse.debug.internal.ui.views.memory.renderings;
 
@@ -39,9 +40,10 @@
 		String paddedStr = DebugUIPlugin.getDefault().getPreferenceStore().getString(IDebugUIConstants.PREF_PADDED_STR);
 
 		if (endianess == RenderingsUtil.LITTLE_ENDIAN) {
+			int addressableSize = getAddressableSize();
 			MemoryByte[] swapped = new MemoryByte[data.length];
-			for (int i = 0; i < data.length; i++){
-				swapped[data.length-i-1] = data[i];
+			for (int i = 0; i < data.length; i += addressableSize) {
+				System.arraycopy(data, i, swapped, data.length - i - addressableSize, addressableSize);
 			}
 			data = swapped;
 		}
@@ -82,9 +84,10 @@
 
 
 		if (endianess == RenderingsUtil.LITTLE_ENDIAN) {
+			int addressableSize = getAddressableSize();
 			byte[] swapped = new byte[bytes.length];
-			for (int i = 0; i < bytes.length; i++){
-				swapped[bytes.length-i-1] = bytes[i];
+			for (int i = 0; i < bytes.length; i += addressableSize) {
+				System.arraycopy(bytes, i, swapped, bytes.length - i - addressableSize, addressableSize);
 			}
 			bytes = swapped;
 		}