/******************************************************************************* * Copyright (c) 2006, 2016 Wind River Systems, Inc. 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: * Ted R Williams (Wind River Systems, Inc.) - initial implementation *******************************************************************************/ package org.eclipse.cdt.debug.ui.memory.transport; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.math.BigInteger; import org.eclipse.cdt.debug.ui.memory.transport.model.IMemoryExporter; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.model.IMemoryBlock; import org.eclipse.debug.core.model.IMemoryBlockExtension; import org.eclipse.debug.core.model.MemoryByte; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.swt.SWT; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.FormAttachment; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.layout.FormLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; public class SRecordExporter implements IMemoryExporter { File fOutputFile; BigInteger fStartAddress; BigInteger fEndAddress; private Text fStartText; private Text fEndText; private Text fLengthText; private Text fFileText; private IMemoryBlock fMemoryBlock; private ExportMemoryDialog fParentDialog; private IDialogSettings fProperties; public Control createControl(final Composite parent, IMemoryBlock memBlock, IDialogSettings properties, ExportMemoryDialog parentDialog) { fMemoryBlock = memBlock; fParentDialog = parentDialog; fProperties = properties; Composite composite = new Composite(parent, SWT.NONE) { public void dispose() { fProperties.put(TRANSFER_FILE, fFileText.getText().trim()); fProperties.put(TRANSFER_START, fStartText.getText().trim()); fProperties.put(TRANSFER_END, fEndText.getText().trim()); try { fStartAddress = getStartAddress(); fEndAddress = getEndAddress(); fOutputFile = getFile(); } catch(Exception e) {} super.dispose(); } }; FormLayout formLayout = new FormLayout(); formLayout.spacing = 5; formLayout.marginWidth = formLayout.marginHeight = 9; composite.setLayout(formLayout); // start address Label startLabel = new Label(composite, SWT.NONE); startLabel.setText(Messages.getString("SRecordExporter.StartAddress")); //$NON-NLS-1$ FormData data = new FormData(); startLabel.setLayoutData(data); fStartText = new Text(composite, SWT.BORDER); data = new FormData(); data.left = new FormAttachment(startLabel); data.width = 120; fStartText.setLayoutData(data); // end address Label endLabel = new Label(composite, SWT.NONE); endLabel.setText(Messages.getString("SRecordExporter.EndAddress")); //$NON-NLS-1$ data = new FormData(); data.top = new FormAttachment(fStartText, 0, SWT.CENTER); data.left = new FormAttachment(fStartText); endLabel.setLayoutData(data); fEndText = new Text(composite, SWT.BORDER); data = new FormData(); data.top = new FormAttachment(fStartText, 0, SWT.CENTER); data.left = new FormAttachment(endLabel); data.width = 120; fEndText.setLayoutData(data); // length Label lengthLabel = new Label(composite, SWT.NONE); lengthLabel.setText(Messages.getString("SRecordExporter.Length")); //$NON-NLS-1$ data = new FormData(); data.top = new FormAttachment(fStartText, 0, SWT.CENTER); data.left = new FormAttachment(fEndText); lengthLabel.setLayoutData(data); fLengthText = new Text(composite, SWT.BORDER); data = new FormData(); data.top = new FormAttachment(fStartText, 0, SWT.CENTER); data.left = new FormAttachment(lengthLabel); data.width = 120; fLengthText.setLayoutData(data); // file Label fileLabel = new Label(composite, SWT.NONE); fFileText = new Text(composite, SWT.BORDER); Button fileButton = new Button(composite, SWT.PUSH); fileLabel.setText(Messages.getString("Exporter.FileName")); //$NON-NLS-1$ data = new FormData(); data.top = new FormAttachment(fileButton, 0, SWT.CENTER); fileLabel.setLayoutData(data); data = new FormData(); data.top = new FormAttachment(fileButton, 0, SWT.CENTER); data.left = new FormAttachment(fileLabel); data.width = 360; fFileText.setLayoutData(data); fileButton.setText(Messages.getString("Exporter.Browse")); //$NON-NLS-1$ data = new FormData(); data.top = new FormAttachment(fLengthText); data.left = new FormAttachment(fFileText); fileButton.setLayoutData(data); // Restriction notice about 32-bit support Label spacingLabel = new Label(composite, SWT.NONE); spacingLabel.setText(""); //$NON-NLS-1$ data = new FormData(); data.left = new FormAttachment(0); data.top = new FormAttachment(fileLabel); spacingLabel.setLayoutData(data); Label restrictionLabel = new Label(composite, SWT.NONE); restrictionLabel.setText(Messages.getString("SRecordExporter.32BitLimitationMessage")); //$NON-NLS-1$ data = new FormData(); data.left = new FormAttachment(0); data.top = new FormAttachment(spacingLabel); restrictionLabel.setLayoutData(data); String textValue = fProperties.get(TRANSFER_FILE); fFileText.setText(textValue != null ? textValue : ""); //$NON-NLS-1$ textValue = fProperties.get(TRANSFER_START); fStartText.setText(textValue != null ? textValue : "0x0"); //$NON-NLS-1$ try { getStartAddress(); } catch(Exception e) { fStartText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); } textValue = fProperties.get(TRANSFER_END); fEndText.setText(textValue != null ? textValue : "0x0"); //$NON-NLS-1$ try { getEndAddress(); } catch(Exception e) { fEndText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); } try { BigInteger length = getEndAddress().subtract(getStartAddress()); fLengthText.setText(length.toString()); if(length.compareTo(BigInteger.ZERO) <= 0) { fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); } } catch(Exception e) { fLengthText.setText("0"); fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); } fileButton.addSelectionListener(new SelectionListener() { public void widgetDefaultSelected(SelectionEvent e) { // TODO Auto-generated method stub } public void widgetSelected(SelectionEvent e) { FileDialog dialog = new FileDialog(parent.getShell(), SWT.SAVE); dialog.setText(Messages.getString("SRecordExporter.ChooseFile")); //$NON-NLS-1$ dialog.setFilterExtensions(new String[] { "*.*;*" } ); //$NON-NLS-1$ dialog.setFilterNames(new String[] { Messages.getString("Exporter.AllFiles") } ); //$NON-NLS-1$ dialog.setFileName(fFileText.getText().trim()); dialog.open(); String filename = dialog.getFileName(); if(filename != null && filename.length() != 0 ) { fFileText.setText(dialog.getFilterPath() + File.separator + filename); } validate(); } }); fStartText.addKeyListener(new KeyListener() { public void keyReleased(KeyEvent e) { try { fStartText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK)); fEndText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK)); fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK)); BigInteger startAddress = getStartAddress(); BigInteger actualLength = getEndAddress().subtract(startAddress); fLengthText.setText(actualLength.toString()); if(actualLength.compareTo(BigInteger.ZERO) <= 0) { fStartText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); } if(startAddress.compareTo(BigInteger.ZERO) < 0) { fStartText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); } BigInteger endAddress = getEndAddress(); if(endAddress.compareTo(BigInteger.ZERO) < 0) { fEndText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); } } catch(Exception ex) { fStartText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); } validate(); } public void keyPressed(KeyEvent e) {} }); fEndText.addKeyListener(new KeyListener() { public void keyReleased(KeyEvent e) { try { fStartText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK)); fEndText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK)); fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK)); BigInteger actualLength = getEndAddress().subtract(getStartAddress()); fLengthText.setText(actualLength.toString()); if(actualLength.compareTo(BigInteger.ZERO) <= 0) { fEndText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); } BigInteger startAddress = getStartAddress(); if(startAddress.compareTo(BigInteger.ZERO) < 0) { fStartText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); } BigInteger endAddress = getEndAddress(); if(endAddress.compareTo(BigInteger.ZERO) < 0) { fEndText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); } } catch(Exception ex) { fEndText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); } validate(); } public void keyPressed(KeyEvent e) {} }); fLengthText.addKeyListener(new KeyListener() { public void keyReleased(KeyEvent e) { try { fStartText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK)); fEndText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK)); fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK)); fStartText.setText(fStartText.getText().trim()); BigInteger length = getLength(); String endString; BigInteger startAddress = getStartAddress(); BigInteger endAddress = startAddress.add(length); if(length.compareTo(BigInteger.ZERO) <= 0) { if(endAddress.compareTo(BigInteger.ZERO) < 0) { endString = endAddress.toString(16); //$NON-NLS-1$ } else { endString = "0x" + endAddress.toString(16); //$NON-NLS-1$ } } else { endString = "0x" + endAddress.toString(16); //$NON-NLS-1$ } fEndText.setText(endString); if(length.compareTo(BigInteger.ZERO) <= 0) { fEndText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); } if(startAddress.compareTo(BigInteger.ZERO) < 0) { fStartText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); } if(endAddress.compareTo(BigInteger.ZERO) < 0) { fEndText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); } } catch(Exception ex) { if ( fLengthText.getText().trim().length() != 0 ) { fEndText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); } fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); } validate(); } public void keyPressed(KeyEvent e) { } }); fFileText.addKeyListener(new KeyListener() { public void keyReleased(KeyEvent e) { validate(); } public void keyPressed(KeyEvent e) { } }); composite.pack(); parent.pack(); /* * We need to perform a validation. If we do it immediately we will get an exception * because things are not totally setup. So we schedule an immediate running of the * validation. For a very brief time the view logically may show a state which does * not reflect the true state of affairs. But the validate immediately corrects the * info. In practice the user never sees the invalid state displayed, because of the * speed of the draw of the dialog. */ Display.getDefault().asyncExec(new Runnable(){ public void run() { validate(); } }); return composite; } public BigInteger getEndAddress() { String text = fEndText.getText(); text = text.trim(); boolean hex = text.startsWith("0x"); //$NON-NLS-1$ BigInteger endAddress = new BigInteger(hex ? text.substring(2) : text, hex ? 16 : 10); if ( endAddress.bitLength() > 32 ) { throw(new NumberFormatException("End Address is larger than 32 bits")); } return endAddress; } public BigInteger getStartAddress() { String text = fStartText.getText(); text = text.trim(); boolean hex = text.startsWith("0x"); //$NON-NLS-1$ BigInteger startAddress = new BigInteger(hex ? text.substring(2) : text, hex ? 16 : 10); if ( startAddress.bitLength() > 32 ) { throw(new NumberFormatException("Start Address is larger than 32 bits")); } return startAddress; } public BigInteger getLength() { String text = fLengthText.getText(); text = text.trim(); boolean hex = text.startsWith("0x"); //$NON-NLS-1$ BigInteger lengthAddress = new BigInteger(hex ? text.substring(2) : text, hex ? 16 : 10); return lengthAddress; } public File getFile() { return new File(fFileText.getText().trim()); } private void validate() { boolean isValid = true; try { getEndAddress(); getStartAddress(); BigInteger length = getLength(); if(length.compareTo(BigInteger.ZERO) <= 0) isValid = false; if ( fFileText.getText().trim().length() == 0 ) isValid = false; File file = getFile(); if ( file != null ) { File parentFile = file.getParentFile(); if(parentFile != null && ! parentFile.exists() ) isValid = false; if(parentFile != null && parentFile.exists() && ( ! parentFile.canRead() || ! parentFile.isDirectory() ) ) isValid = false; if ( file.isDirectory() ) isValid = false; } } catch(Exception e) { isValid = false; } fParentDialog.setValid(isValid); } public String getId() { return "srecord"; //$NON-NLS-1$ } public String getName() { return Messages.getString("SRecordExporter.Name"); //$NON-NLS-1$ } public void exportMemory() { Job job = new Job("Memory Export to S-Record File"){ //$NON-NLS-1$ public IStatus run(IProgressMonitor monitor) { try { // FIXME 4 byte default BigInteger DATA_PER_RECORD = BigInteger.valueOf(16); BigInteger transferAddress = fStartAddress; FileWriter writer = new FileWriter(fOutputFile); BigInteger jobs = fEndAddress.subtract(transferAddress).divide(DATA_PER_RECORD); BigInteger factor = BigInteger.ONE; if(jobs.compareTo(BigInteger.valueOf(0x7FFFFFFF)) > 0) { factor = jobs.divide(BigInteger.valueOf(0x7FFFFFFF)); jobs = jobs.divide(factor); } monitor.beginTask(Messages.getString("Exporter.ProgressTitle"), jobs.intValue()); //$NON-NLS-1$ BigInteger jobCount = BigInteger.ZERO; while(transferAddress.compareTo(fEndAddress) < 0 && !monitor.isCanceled()) { BigInteger length = DATA_PER_RECORD; if(fEndAddress.subtract(transferAddress).compareTo(length) < 0) length = fEndAddress.subtract(transferAddress); monitor.subTask(String.format(Messages.getString("Exporter.Progress"), length.toString(10), transferAddress.toString(16))); //$NON-NLS-1$ writer.write("S3"); // FIXME 4 byte address //$NON-NLS-1$ StringBuilder buf = new StringBuilder(); BigInteger sRecordLength = BigInteger.valueOf(4); // address size sRecordLength = sRecordLength.add(length); sRecordLength = sRecordLength.add(BigInteger.ONE); // checksum String transferAddressString = transferAddress.toString(16); String lengthString = sRecordLength.toString(16); if(lengthString.length() == 1) buf.append("0"); //$NON-NLS-1$ buf.append(lengthString); for(int i = 0; i < 8 - transferAddressString.length(); i++) buf.append("0"); //$NON-NLS-1$ buf.append(transferAddressString); // data MemoryByte bytes[] = ((IMemoryBlockExtension) fMemoryBlock).getBytesFromAddress(transferAddress, length.longValue() / ((IMemoryBlockExtension) fMemoryBlock).getAddressableSize()); for(int byteIndex = 0; byteIndex < bytes.length; byteIndex++) { String bString = BigInteger.valueOf(0xFF & bytes[byteIndex].getValue()).toString(16); if(bString.length() == 1) buf.append("0"); //$NON-NLS-1$ buf.append(bString); } /* * The least significant byte of the one's complement of the sum of the values * represented by the pairs of characters making up the records length, address, * and the code/data fields. */ byte checksum = 0; for(int i = 0; i < buf.length(); i+=2) { BigInteger value = new BigInteger(buf.substring(i, i+2), 16); checksum += value.byteValue(); } String bString = BigInteger.valueOf(0xFF - checksum).and(BigInteger.valueOf(0xFF)).toString(16); if(bString.length() == 1) buf.append("0"); //$NON-NLS-1$ buf.append(bString); writer.write(buf.toString().toUpperCase()); writer.write("\n"); //$NON-NLS-1$ transferAddress = transferAddress.add(length); jobCount = jobCount.add(BigInteger.ONE); if(jobCount.compareTo(factor) == 0) { jobCount = BigInteger.ZERO; monitor.worked(1); } } writer.close(); monitor.done(); } catch (IOException ex) { MemoryTransportPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(), DebugException.REQUEST_FAILED, Messages.getString("Exporter.ErrFile"), ex)); //$NON-NLS-1$ return new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(), DebugException.REQUEST_FAILED, Messages.getString("Exporter.ErrFile"), ex); //$NON-NLS-1$ } catch (DebugException ex) { MemoryTransportPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(), DebugException.REQUEST_FAILED, Messages.getString("Exporter.ErrReadTarget"), ex)); //$NON-NLS-1$ return new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(), DebugException.REQUEST_FAILED, Messages.getString("Exporter.ErrReadTarget"), ex); //$NON-NLS-1$ } catch (Exception ex) { MemoryTransportPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(), DebugException.INTERNAL_ERROR, Messages.getString("Exporter.Falure"), ex)); //$NON-NLS-1$ return new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(), DebugException.INTERNAL_ERROR, Messages.getString("Exporter.Falure"), ex); //$NON-NLS-1$ } return Status.OK_STATUS; }}; job.setUser(true); job.schedule(); } }