001package jmri.jmrix.pricom.downloader; 002 003import java.io.BufferedInputStream; 004import java.io.File; 005import java.io.FileInputStream; 006import java.io.IOException; 007import java.io.InputStream; 008import org.slf4j.Logger; 009import org.slf4j.LoggerFactory; 010 011/** 012 * Support for reading PRICOM ".pdi" files 013 * <p> 014 * The PRICOM format documentation is Copyright 2003, 2005, PRICOM Corp. They 015 * have kindly given permission for this use. 016 * 017 * @author Bob Jacobsen Copyright (C) 2005 018 */ 019public class PdiFile { 020 021 public PdiFile(File file) { 022 this.file = file; 023 } 024 025 File file; 026 private InputStream buffIn; 027 028 String comment = ""; 029 int commentLength; 030 031 int lastAddress; 032 int address; 033 034 int fileLength; 035 036 public void open() throws IOException { 037 InputStream stream = new BufferedInputStream(new FileInputStream(file)); 038 open(stream); 039 } 040 041 public void open(InputStream stream) throws IOException { 042 buffIn = stream; 043 044 // get comment length, comment 045 int high = (buffIn.read() & 0xFF); 046 int low = (buffIn.read() & 0xFF); 047 commentLength = high * 256 + low; 048 049 StringBuffer buffer = new StringBuffer(); 050 051 // Note the count is decremented by two in the following. 052 // Apparently, the comment length field includes it's own 053 // two bytes in the count 054 for (int i = 0; i < (commentLength - 2); i++) { 055 int next = buffIn.read(); 056 if (next == 0x0d) { 057 buffer.append("\n"); 058 } else if (next != 0x0a) { 059 buffer.append((char) next); 060 } 061 } 062 063 comment = buffer.toString(); 064 065 // get data base address 066 high = (buffIn.read() & 0xFF); 067 low = (buffIn.read() & 0xFF); 068 address = high * 256 + low; 069 if (log.isDebugEnabled()) { 070 log.debug("address {} {}", high, low); 071 } 072 073 // get last address to write 074 high = (buffIn.read() & 0xFF); 075 low = (buffIn.read() & 0xFF); 076 lastAddress = high * 256 + low; 077 if (log.isDebugEnabled()) { 078 log.debug("length {} {}", high, low); 079 } 080 081 fileLength = (int) file.length() - 6 - commentLength; 082 083 if (log.isDebugEnabled()) { 084 log.debug("lengths: file {}, comment {}, data {}", (int) file.length(), commentLength, lastAddress); 085 } 086 } 087 088 /** 089 * Return the comment embedded at the front of the file. 090 * @return file comment. 091 */ 092 public String getComment() { 093 return comment; 094 } 095 096 int length() { 097 return fileLength; 098 } 099 100 /** 101 * Get the next n bytes for transmission to the device 102 * 103 * @param n number of data bytes to include 104 * @return byte buffer, starting with address info and containing data, but 105 * not CRC 106 */ 107 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "PZLA_PREFER_ZERO_LENGTH_ARRAYS", 108 justification = "API defined by Pricom docs") 109 public byte[] getNext(int n) { 110 byte[] buffer = new byte[n + 3 + 2]; // 3 at front, 2 at back for CRC 111 int rd; 112 113 // load header 114 if (n == 128) { 115 buffer[0] = 60; 116 } else { 117 buffer[0] = 59; 118 } 119 120 buffer[1] = (byte) ((address >> 8) & 0xFF); 121 buffer[2] = (byte) (address & 0xFF); 122 address = address + n; 123 124 for (int i = 0; i < n + 2; i++) { 125 buffer[3 + i] = 0; // clear data section 126 } 127 try { 128 // fill data 129 for (int i = 0; i < n; i++) { 130 rd = buffIn.read(); // read from file, -1=EOF 131 if (rd == -1) { 132 return null; // return NULL pointer 133 } 134 buffer[3 + i] = (byte) (rd & 0xFF); // tuck the byte 135 } 136 } catch (IOException e) { 137 log.error("IO exception reading file", e); 138 } 139 return buffer; 140 } 141 142 private final static Logger log = LoggerFactory.getLogger(PdiFile.class); 143}