001/* 002 * Copyright (c) 2002-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: crawl $' 006 * '$Date: 2016-07-13 00:37:38 +0000 (Wed, 13 Jul 2016) $' 007 * '$Revision: 34505 $' 008 * 009 * Permission is hereby granted, without written agreement and without 010 * license or royalty fees, to use, copy, modify, and distribute this 011 * software and its documentation for any purpose, provided that the above 012 * copyright notice and the following two paragraphs appear in all copies 013 * of this software. 014 * 015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 019 * SUCH DAMAGE. 020 * 021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 026 * ENHANCEMENTS, OR MODIFICATIONS. 027 * 028 */ 029 030package org.geon; 031 032import java.io.IOException; 033import java.io.InputStream; 034import java.net.URL; 035 036import ptolemy.actor.TypedIOPort; 037import ptolemy.actor.lib.Source; 038import ptolemy.data.ArrayToken; 039import ptolemy.data.BooleanToken; 040import ptolemy.data.StringToken; 041import ptolemy.data.Token; 042import ptolemy.data.UnsignedByteToken; 043import ptolemy.data.expr.FileParameter; 044import ptolemy.data.expr.Parameter; 045import ptolemy.data.type.ArrayType; 046import ptolemy.data.type.BaseType; 047import ptolemy.kernel.CompositeEntity; 048import ptolemy.kernel.util.IllegalActionException; 049import ptolemy.kernel.util.NameDuplicationException; 050import ptolemy.kernel.util.Workspace; 051 052////////////////////////////////////////////////////////////////////////// 053//// BinaryFileReader 054/** 055 * This actor reads a file or URL and outputs its content as a bytes array. At 056 * each iteration a chunk of bytes is read from the file and outputed as a bytes 057 * array. 058 * 059 * @UserLevelDocumentation This actor reads binary files and streams its content 060 * as a bytes array. 061 * @author Efrat Jaeger 062 * @version $Id: BinaryFileReader.java 34505 2016-07-13 00:37:38Z crawl $ 063 * @since Ptolemy II 3.0.2 064 */ 065public class BinaryFileReader extends Source { 066 067 /** 068 * Construct an actor with the given container and name. 069 * 070 * @param container 071 * The container. 072 * @param name 073 * The name of this actor. 074 * @exception IllegalActionException 075 * If the actor cannot be contained by the proposed 076 * container. 077 * @exception NameDuplicationException 078 * If the container already has an actor with this name. 079 */ 080 public BinaryFileReader(CompositeEntity container, String name) 081 throws IllegalActionException, NameDuplicationException { 082 super(container, name); 083 084 output.setTypeEquals(new ArrayType(BaseType.UNSIGNED_BYTE)); 085 086 endOfFile = new TypedIOPort(this, "endOfFile", false, true); 087 endOfFile.setTypeEquals(BaseType.BOOLEAN); 088 089 fileOrURL = new FileParameter(this, "fileOrURL"); 090 091 fileOrURLPort = new TypedIOPort(this, "fileOrURLPort", true, false); 092 fileOrURLPort.setTypeEquals(BaseType.STRING); 093 094 readAll = new Parameter(this, "readAll"); 095 readAll.setTypeEquals(BaseType.BOOLEAN); 096 readAll.setToken(BooleanToken.FALSE); 097 098 _attachText("_iconDescription", "<svg>\n" 099 + "<rect x=\"-25\" y=\"-20\" " + "width=\"50\" height=\"40\" " 100 + "style=\"fill:white\"/>\n" 101 + "<polygon points=\"-15,-10 -12,-10 -8,-14 -1,-14 3,-10" 102 + " 15,-10 15,10, -15,10\" " + "style=\"fill:red\"/>\n" 103 + "</svg>\n"); 104 } 105 106 // ///////////////////////////////////////////////////////////////// 107 // // ports and parameters //// 108 109 /** 110 * An output port that produces false until the end of file is reached, at 111 * which point it produces true. The type is boolean. 112 * 113 * @UserLevelDocumentation An output port that produces false until the end 114 * of file is reached, at which point it produces 115 * true. 116 */ 117 public TypedIOPort endOfFile; 118 119 /** 120 * The file name or URL from which to read. This is a string with any form 121 * accepted by FileParameter. 122 * 123 * @UserLevelDocumentation The path to the file to be read. 124 * @see FileParameter 125 */ 126 public FileParameter fileOrURL; 127 128 /** 129 * An input for optionally providing a file name. 130 * 131 * @UserLevelDocumentation An input port for passing a file path sent from a 132 * previous step in the workflow. 133 * @see FileParameter 134 */ 135 public TypedIOPort fileOrURLPort; 136 137 /** If true, read the entire contents of the file at once. */ 138 public Parameter readAll; 139 140 // ///////////////////////////////////////////////////////////////// 141 // // public methods //// 142 143 /** 144 * Clone the actor into the specified workspace. 145 * 146 * @return A new actor. 147 * @exception CloneNotSupportedException 148 * If a derived class contains an attribute that cannot be 149 * cloned. 150 */ 151 @Override 152 public Object clone(Workspace workspace) throws CloneNotSupportedException { 153 BinaryFileReader newObject = (BinaryFileReader) super.clone(workspace); 154 newObject._nBytesRead = 0; 155 newObject._bytesRead = null; 156 newObject._newFile = true; 157 newObject._previousFileOrURL = null; 158 newObject._reader = null; 159 return newObject; 160 } 161 162 /** 163 * Output the data read initially in the prefire() than in each invocation 164 * of postfire(), if there is any. 165 * 166 * @exception IllegalActionException 167 * If there's no director. 168 */ 169 @Override 170 public void fire() throws IllegalActionException { 171 super.fire(); 172 if (_nBytesRead > 0) { 173 Token _bytes[] = new Token[_nBytesRead]; 174 for (int i = 0; i < _nBytesRead; i++) { 175 _bytes[i] = new UnsignedByteToken(_bytesRead[i]); 176 } 177 output.send(0, new ArrayToken(_bytes)); 178 } 179 } 180 181 /** 182 * If this is called after prefire() has been called but before wrapup() has 183 * been called, then close any open file. 184 * 185 * @exception IllegalActionException 186 * If the file or URL cannot be opened or read. 187 */ 188 @Override 189 public void initialize() throws IllegalActionException { 190 super.initialize(); 191 _reader = null; 192 fileOrURL.close(); 193 } 194 195 /** 196 * Read the next bytes from the file. If there reached EOF, return false. 197 * Otherwise, return whatever the superclass returns. 198 * 199 * @exception IllegalActionException 200 * If there is a problem reading the file. 201 */ 202 @Override 203 public boolean postfire() throws IllegalActionException { 204 if (_reader == null) { 205 return false; 206 } 207 try { 208 _nBytesRead = _reader.read(_bytesRead); 209 if (_nBytesRead <= 0) { 210 // In case the return value gets ignored by the domain: 211 _newFile = true; 212 endOfFile.broadcast(BooleanToken.TRUE); 213 String fileNameStr = ((StringToken) fileOrURL.getToken()) 214 .stringValue(); 215 // If the fileName is read from a parameter and hasn't changed - 216 // meaning there is no next file to read. 217 if (fileOrURLPort.getWidth() == 0 218 && fileNameStr.equals(_previousFileOrURL)) { 219 return false; 220 } 221 } else { 222 endOfFile.broadcast(BooleanToken.FALSE); 223 } 224 return super.postfire(); 225 } catch (IOException ex) { 226 throw new IllegalActionException(this, ex, "Postfire failed"); 227 } 228 } 229 230 /** 231 * If this method is called after wrapup() has been called, then open the 232 * file, and read the first chunk of bytes Return false if there is no more 233 * data available in the file. Otherwise, return whatever the superclass 234 * returns. 235 * 236 * @exception IllegalActionException 237 * If the superclass throws it. 238 */ 239 @Override 240 public boolean prefire() throws IllegalActionException { 241 if (_newFile) { 242 if (fileOrURLPort.getWidth() > 0) { 243 if (fileOrURLPort.hasToken(0)) { 244 String name = ((StringToken) fileOrURLPort.get(0)) 245 .stringValue(); 246 int lineEndInd = name.indexOf("\n"); 247 if (lineEndInd != -1) // if the string contains a CR. 248 name = name.substring(0, lineEndInd); 249 fileOrURL.setExpression(name); 250 } 251 } 252 String fileNameStr = ((StringToken) fileOrURL.getToken()) 253 .stringValue(); 254 /* 255 * if (fileNameStr.equals(_previousFileOrURL)) { _reader = null; 256 * return false; } else 257 */ 258 _previousFileOrURL = fileNameStr; 259 260 _openAndReadFirstBytes(); 261 _newFile = false; 262 } 263 264 // if (_reachedEOF) return false; 265 // else 266 return super.prefire(); 267 } 268 269 /** 270 * Close the reader if there is one. 271 * 272 * @exception IllegalActionException 273 * If an IO error occurs. 274 */ 275 @Override 276 public void wrapup() throws IllegalActionException { 277 super.wrapup(); 278 fileOrURL.close(); 279 _reader = null; 280 _newFile = true; 281 _previousFileOrURL = null; 282 _bytesRead = null; 283 } 284 285 // ///////////////////////////////////////////////////////////////// 286 // // protected members //// 287 288 /** number of bytes read. */ 289 protected int _nBytesRead; 290 291 /** The current bytes read. */ 292 protected byte[] _bytesRead; 293 294 /** The current reader for the input file. */ 295 protected InputStream _reader; 296 297 // ///////////////////////////////////////////////////////////////// 298 // // private methods //// 299 300 /** 301 * Open the file and read the first bytes. 302 */ 303 private void _openAndReadFirstBytes() throws IllegalActionException { 304 URL url = fileOrURL.asURL(); 305 if (url == null) { 306 throw new IllegalActionException(this, 307 "No file name has been specified."); 308 } 309 try { 310 _reader = url.openStream(); 311 } catch (IOException ex) { 312 throw new IllegalActionException(this, ex, 313 "Cannot open file or URL"); 314 } 315 316 317 Token token = readAll.getToken(); 318 if(token == null || !((BooleanToken)token).booleanValue()) { 319 _bytesRead = new byte[DEFAULT_BUFFER_SIZE]; 320 } else { 321 _bytesRead = new byte[Long.valueOf(fileOrURL.asFile().length()).intValue()]; 322 } 323 324 try { 325 _nBytesRead = _reader.read(_bytesRead); 326 } catch (IOException ex) { 327 throw new IllegalActionException(this, ex, "Preinitialize failed."); 328 } 329 } 330 331 // ///////////////////////////////////////////////////////////////// 332 // // private members //// 333 334 /** Previous value of fileOrURL parameter. */ 335 private String _previousFileOrURL; 336 337 /** Indicator to open a new file in the prefire */ 338 private boolean _newFile = true; 339 340 /** Number of bytes in read buffer if readAll parameter is false. */ 341 private final static int DEFAULT_BUFFER_SIZE = 20000; 342}