/******************************************************************************* * Copyright (c) 2004, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.debug.internal.ui.views.memory.renderings; import java.util.ArrayList; import org.eclipse.core.runtime.PlatformObject; import org.eclipse.debug.core.model.MemoryByte; /** * @since 3.0 */ public class TableRenderingLine extends PlatformObject { private String fAddress; private String fStrRep; private MemoryByte[] fBytes; private byte[] fByteArray; private int fTableIndex = -1; private String fPaddedString; public boolean isMonitored; public static final String P_ADDRESS = "address"; //$NON-NLS-1$ // for raw hex data, it's 2 characters per byte private static final int numCharPerByteForHex = 2; public TableRenderingLine(String address, MemoryByte[] bytes, int tableIndex, String paddedString) { fAddress = address; fBytes = bytes; fTableIndex = tableIndex; fPaddedString = paddedString; } public String getAddress() { return fAddress; } public void setAddress(String address) { fAddress = address; } public MemoryByte[] getBytes() { return fBytes; } public MemoryByte getByte(int offset) { if (fBytes == null) return null; if (offset < fBytes.length) { return fBytes[offset]; } return null; } public MemoryByte[] getBytes(int start, int end) { ArrayList<MemoryByte> ret = new ArrayList<MemoryByte>(); for (int i=start; i<end; i++) { ret.add(fBytes[i]); } return ret.toArray(new MemoryByte[ret.size()]); } public String getRawMemoryString() { if (fStrRep == null) { StringBuffer buffer = new StringBuffer(); fStrRep = RenderingsUtil.convertByteArrayToHexString(getByteArray()); fStrRep = fStrRep.toUpperCase(); buffer = buffer.append(fStrRep); // pad unavailable bytes with padded string from memory block String paddedString = null; int bufferCounter = 0; for (int i=0; i<fBytes.length; i++) { // if byte is invalid if (!fBytes[i].isReadable()) { if (paddedString == null) { paddedString = fPaddedString; if (paddedString.length() > TableRenderingLine.numCharPerByteForHex) paddedString = paddedString.substring(0, TableRenderingLine.numCharPerByteForHex); } buffer.replace(bufferCounter, bufferCounter+TableRenderingLine.numCharPerByteForHex, paddedString); } bufferCounter += TableRenderingLine.numCharPerByteForHex; } fStrRep = buffer.toString(); } return fStrRep; } /** * @param start * @param end * @return is the bytes between start and end are all valid */ public boolean isAvailable(int start, int end) { boolean available = true; for (int i=start; i<end; i++) { if (!fBytes[i].isReadable()) { available = false; break; } } return available; } public byte[] getByteArray() { if (fByteArray == null) { fByteArray = new byte[fBytes.length]; for (int i=0; i<fBytes.length; i++) { fByteArray[i] = fBytes[i].getValue(); } } return fByteArray; } public byte[] getByteArray(int start, int end) { byte[] ret = new byte[end-start]; int j=0; for (int i=start; i<end; i++) { ret[j] = fBytes[i].getValue(); j++; } return ret; } public void markDeltas(TableRenderingLine oldData) { if (oldData == null) return; // if address is not the same, no need to compare if (!oldData.getAddress().equals(this.getAddress())) return; // if the string representation is the same, no need to compare if (oldData.getRawMemoryString().equals(getRawMemoryString())) { for (int i=0; i<fBytes.length; i++) { // set history as known if we have old data for this line fBytes[i].setHistoryKnown(true); } return; } MemoryByte[] oldMemory = oldData.getBytes(); if (oldMemory.length != fBytes.length) return; for (int i=0; i<fBytes.length; i++) { // turn on known bit fBytes[i].setHistoryKnown(true); if ((fBytes[i].getFlags() & MemoryByte.READABLE) != (oldMemory[i].getFlags() & MemoryByte.READABLE)) { fBytes[i].setChanged(true); continue; } if (fBytes[i].isReadable() && oldMemory[i].isReadable()) { if (fBytes[i].getValue() != oldMemory[i].getValue()) { fBytes[i].setChanged(true); } } } } public void copyDeltas(TableRenderingLine oldData) { if (oldData == null) return; // if address is not the same, do not copy if (!oldData.getAddress().equals(this.getAddress())) return; // reuse delta information from old data MemoryByte[] oldMemory = oldData.getBytes(); if (oldMemory.length != fBytes.length) return; for (int i=0; i<fBytes.length; i++) { fBytes[i].setFlags(oldMemory[i].getFlags()); } } public boolean isLineChanged(TableRenderingLine oldData) { if (oldData == null) return false; // if address is not the same, no need to compare if (!oldData.getAddress().equals(this.getAddress())) return false; // if the string representation is not the same, this line has changed if (oldData.getRawMemoryString().equals(getRawMemoryString())) { return false; } return true; } /** * @param offset * @param endOffset * @return true if the specified range of memory has changed, false otherwise * */ public boolean isRangeChange(int offset, int endOffset) { boolean allBytesKnown = true; boolean allBytesUnchanged = true; for (int i=offset; i<=endOffset; i++) { if (!fBytes[i].isHistoryKnown()) allBytesKnown = false; if (fBytes[i].isChanged()) allBytesUnchanged = false; } if (allBytesKnown && !allBytesUnchanged) { return true; } return false; } public void unmarkDeltas() { for (int i=0; i<fBytes.length; i++) { // unset the change bit if (fBytes[i].isChanged()) fBytes[i].setChanged(false); } } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer buf = new StringBuffer(); buf.append(getAddress()); buf.append(": "); //$NON-NLS-1$ buf.append(getRawMemoryString()); return buf.toString(); } public int getTableIndex() { return fTableIndex; } public int getLength() { return fBytes.length; } }