| /******************************************************************************* |
| * 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 ret = new ArrayList(); |
| |
| for (int i=start; i<end; i++) |
| { |
| ret.add(fBytes[i]); |
| } |
| return (MemoryByte[]) 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() |
| */ |
| 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; |
| } |
| |
| } |
| |