/******************************************************************************* * 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.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.math.BigInteger; import org.eclipse.cdt.debug.ui.memory.transport.model.IMemoryImporter; 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.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.ModifyEvent; import org.eclipse.swt.events.ModifyListener; 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 SRecordImporter implements IMemoryImporter { File fInputFile; BigInteger fStartAddress; Boolean fScrollToStart; private Text fStartText; private Text fFileText; private Button fComboRestoreToThisAddress; private Button fComboRestoreToFileAddress; private Button fScrollToBeginningOnImportComplete; private IMemoryBlock fMemoryBlock; private ImportMemoryDialog fParentDialog; private IDialogSettings fProperties; private static final int BUFFER_LENGTH = 64 * 1024; public Control createControl(final Composite parent, IMemoryBlock memBlock, IDialogSettings properties, ImportMemoryDialog 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_SCROLL_TO_START, fScrollToBeginningOnImportComplete.getSelection()); fProperties.put(TRANSFER_CUSTOM_START_ADDRESS, fComboRestoreToThisAddress.getSelection()); try { if(fProperties.getBoolean(TRANSFER_CUSTOM_START_ADDRESS)) { fStartAddress = getStartAddress(); } fInputFile = getFile(); fScrollToStart = getScrollToStart(); } catch(Exception e) {} super.dispose(); } }; FormLayout formLayout = new FormLayout(); formLayout.spacing = 5; formLayout.marginWidth = formLayout.marginHeight = 9; composite.setLayout(formLayout); // restore to file address fComboRestoreToFileAddress = new Button(composite, SWT.RADIO); fComboRestoreToFileAddress.setSelection(true); fComboRestoreToFileAddress.setText(Messages.getString("SRecordImporter.FileAddressRestore")); //$NON-NLS-1$ fComboRestoreToFileAddress.setSelection(!fProperties.getBoolean(TRANSFER_CUSTOM_START_ADDRESS)); //comboRestoreToFileAddress.setLayoutData(data); // restore to this address fComboRestoreToThisAddress = new Button(composite, SWT.RADIO); fComboRestoreToThisAddress.setText(Messages.getString("SRecordImporter.CustomAddressRestore")); //$NON-NLS-1$ fComboRestoreToThisAddress.setSelection(fProperties.getBoolean(TRANSFER_CUSTOM_START_ADDRESS)); FormData data = new FormData(); data.top = new FormAttachment(fComboRestoreToFileAddress); fComboRestoreToThisAddress.setLayoutData(data); fStartText = new Text(composite, SWT.BORDER); data = new FormData(); data.top = new FormAttachment(fComboRestoreToFileAddress); data.left = new FormAttachment(fComboRestoreToThisAddress); data.width = 120; fStartText.setLayoutData(data); fComboRestoreToFileAddress.addSelectionListener(new SelectionListener() { public void widgetDefaultSelected(SelectionEvent e) {} public void widgetSelected(SelectionEvent e) { validate(); } }); fComboRestoreToThisAddress.addSelectionListener(new SelectionListener() { public void widgetDefaultSelected(SelectionEvent e) {} public void widgetSelected(SelectionEvent e) { try { fStartText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK)); getStartAddress(); validate(); } catch(Exception ex) { fStartText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); fParentDialog.setValid(false); } } }); // 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("Importer.File")); //$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 = 300; fFileText.setLayoutData(data); fileButton.setText(Messages.getString("Importer.Browse")); //$NON-NLS-1$ data = new FormData(); data.top = new FormAttachment(fStartText); data.left = new FormAttachment(fFileText); fileButton.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$ 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("SRecordImporter.ChooseFile")); //$NON-NLS-1$ dialog.setFilterExtensions(new String[] { "*.*;*" } ); //$NON-NLS-1$ dialog.setFilterNames(new String[] { Messages.getString("Importer.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 { boolean restoreToAddress = fComboRestoreToThisAddress.getSelection(); if ( restoreToAddress ) { fStartText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK)); getStartAddress(); validate(); } else { try { getStartAddress(); fStartText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK)); } catch(Exception ex) { fStartText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); } } } catch(Exception ex) { fStartText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); validate(); } } public void keyPressed(KeyEvent e) {} }); fFileText.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { validate(); } }); fScrollToBeginningOnImportComplete = new Button(composite, SWT.CHECK); fScrollToBeginningOnImportComplete.setText(Messages.getString("SRecordImporter.ScrollToStart")); //$NON-NLS-1$ data = new FormData(); data.top = new FormAttachment(fileButton); fScrollToBeginningOnImportComplete.setLayoutData(data); final boolean scrollToStart = fProperties.getBoolean(TRANSFER_SCROLL_TO_START); fScrollToBeginningOnImportComplete.setSelection(scrollToStart); // 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(fScrollToBeginningOnImportComplete); spacingLabel.setLayoutData(data); Label restrictionLabel = new Label(composite, SWT.NONE); restrictionLabel.setText(Messages.getString("SRecordImporter.32BitLimitationMessage")); //$NON-NLS-1$ data = new FormData(); data.left = new FormAttachment(0); data.top = new FormAttachment(spacingLabel); restrictionLabel.setLayoutData(data); composite.pack(); parent.pack(); Display.getDefault().asyncExec(new Runnable(){ public void run() { validate(); } }); return composite; } private void validate() { boolean isValid = true; try { boolean restoreToAddress = fComboRestoreToThisAddress.getSelection(); if ( restoreToAddress ) { getStartAddress(); } if ( fFileText.getText().trim().length() == 0 ) isValid = false; if(!getFile().exists()) { isValid = false; } } catch(Exception e) { isValid = false; } fParentDialog.setValid(isValid); } public boolean getScrollToStart() { return fScrollToBeginningOnImportComplete.getSelection(); } 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 File getFile() { return new File(fFileText.getText().trim()); } public String getId() { return "srecord"; //$NON-NLS-1$ } public String getName() { return Messages.getString("SRecordImporter.Name"); //$NON-NLS-1$ } public void importMemory() { Job job = new Job("Memory Import from S-Record File"){ //$NON-NLS-1$ public IStatus run(IProgressMonitor monitor) { try { BufferedMemoryWriter memoryWriter = new BufferedMemoryWriter((IMemoryBlockExtension) fMemoryBlock, BUFFER_LENGTH); // FIXME 4 byte default final int CHECKSUM_LENGTH = 1; BigInteger scrollToAddress = null; BigInteger offset = null; if(!fProperties.getBoolean(TRANSFER_CUSTOM_START_ADDRESS)) offset = BigInteger.ZERO; BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(fInputFile))); BigInteger jobs = BigInteger.valueOf(fInputFile.length()); 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("Importer.ProgressTitle"), jobs.intValue()); //$NON-NLS-1$ String line = reader.readLine(); int lineNo = 1; // line error reporting while(line != null && !monitor.isCanceled()) { String recordType = line.substring(0, 2); int recordCount = 0; try { recordCount = Integer.parseInt(line.substring(2, 4), 16); } catch (NumberFormatException ex) { return new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(), DebugException.REQUEST_FAILED, String.format(Messages.getString("SRecordImporter.InvalidLineLength"), lineNo ), ex); //$NON-NLS-1$ } int bytesRead = 4 + recordCount; int position = 4; int addressSize = 0; BigInteger recordAddress = null; if("S3".equals(recordType)) //$NON-NLS-1$ addressSize = 4; else if("S1".equals(recordType)) //$NON-NLS-1$ addressSize = 2; else if("S2".equals(recordType)) //$NON-NLS-1$ addressSize = 3; else if("S0".equals(recordType) || "S5".equals(recordType) ||"S7".equals(recordType) || "S8".equals(recordType) || "S9".equals(recordType) ) //$NON-NLS-1$ { // ignore S0, S5, S7, S8 and S9 records line = reader.readLine(); lineNo++; continue; } try { recordAddress = new BigInteger(line.substring(position, position + addressSize * 2), 16); } catch (NumberFormatException ex) { return new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(), DebugException.REQUEST_FAILED, String.format(Messages.getString("SRecordImporter.InvalidAddress"), lineNo ), ex); //$NON-NLS-1$ } recordCount -= addressSize; position += addressSize * 2; if(offset == null) offset = fStartAddress.subtract(recordAddress); recordAddress = recordAddress.add(offset); byte data[] = new byte[recordCount - CHECKSUM_LENGTH]; for(int i = 0; i < data.length; i++) { try { data[i] = new BigInteger(line.substring(position++, position++ + 1), 16).byteValue(); } catch (NumberFormatException ex) { return new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(), DebugException.REQUEST_FAILED, String.format(Messages.getString("SRecordImporter.InvalidData"), lineNo ), ex); //$NON-NLS-1$ } } /* * 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. */ StringBuilder buf = new StringBuilder(line.substring(2)); byte checksum = 0; for(int i = 0; i < buf.length(); i+=2) { BigInteger value = null; try { value = new BigInteger(buf.substring(i, i+2), 16); } catch (NumberFormatException ex) { return new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(), DebugException.REQUEST_FAILED, String.format(Messages.getString("SRecordImporter.InvalidChecksum"), lineNo ), ex); //$NON-NLS-1$ } checksum += value.byteValue(); } /* * Since we included the checksum in the checksum calculation the checksum * ( if correct ) will always be 0xFF which is -1 using the signed byte size * calculation here. */ if ( checksum != (byte) -1 ) { reader.close(); monitor.done(); return new Status( IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(), Messages.getString("SRecordImporter.ChecksumFalure") + line); //$NON-NLS-1$ } if(scrollToAddress == null) scrollToAddress = recordAddress; // FIXME error on incorrect checksum memoryWriter.write(recordAddress.subtract(((IMemoryBlockExtension) fMemoryBlock).getBigBaseAddress()), data); BigInteger jobCount = BigInteger.valueOf(bytesRead).divide(factor); monitor.worked(jobCount.intValue()); line = reader.readLine(); lineNo++; } if (!monitor.isCanceled()) memoryWriter.flush(); reader.close(); monitor.done(); if (fScrollToStart) fParentDialog.scrollRenderings(scrollToAddress); } catch (IOException ex) { MemoryTransportPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(), DebugException.REQUEST_FAILED, Messages.getString("Importer.ErrReadFile"), ex)); //$NON-NLS-1$ return new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(), DebugException.REQUEST_FAILED, Messages.getString("Importer.ErrReadFile"), ex); //$NON-NLS-1$ } catch (DebugException ex) { MemoryTransportPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(), DebugException.REQUEST_FAILED, Messages.getString("Importer.ErrWriteTarget"), ex)); //$NON-NLS-1$ return new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(), DebugException.REQUEST_FAILED, Messages.getString("Importer.ErrWriteTarget"), ex); //$NON-NLS-1$ } catch (Exception ex) { MemoryTransportPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(), DebugException.INTERNAL_ERROR, Messages.getString("Importer.FalureImporting"), ex)); //$NON-NLS-1$ return new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(), DebugException.INTERNAL_ERROR, Messages.getString("Importer.FalureImporting"), ex); //$NON-NLS-1$ } return Status.OK_STATUS; }}; job.setUser(true); job.schedule(); } }