001    /*
002     * Copyright (C) 2001 Ciaran Treanor <ciaran@codeloop.com>
003     *
004     * Distributable under GPL license.
005     * See terms of license at gnu.org.
006     *
007     * $Id: RRDFile.java,v 1.2 2006/12/21 18:02:42 tarus Exp $
008     */
009    package org.jrobin.core.jrrd;
010    
011    import java.io.*;
012    
013    /**
014     * This class is a quick hack to read information from an RRD file. Writing
015     * to RRD files is not currently supported. As I said, this is a quick hack.
016     * Some thought should be put into the overall design of the file IO.
017     * <p/>
018     * Currently this can read RRD files that were generated on Solaris (Sparc)
019     * and Linux (x86).
020     *
021     * @author <a href="mailto:ciaran@codeloop.com">Ciaran Treanor</a>
022     * @version $Revision: 1.2 $
023     */
024    public class RRDFile implements Constants {
025    
026            boolean bigEndian;
027            int alignment;
028            RandomAccessFile ras;
029            byte[] buffer;
030    
031            RRDFile(String name) throws IOException {
032                    this(new File(name));
033            }
034    
035            RRDFile(File file) throws IOException {
036    
037                    ras = new RandomAccessFile(file, "r");
038                    buffer = new byte[128];
039    
040                    initDataLayout(file);
041            }
042    
043            private void initDataLayout(File file) throws IOException {
044    
045                    if (file.exists()) {    // Load the data formats from the file
046                            ras.read(buffer, 0, 24);
047    
048                            int index;
049    
050                            if ((index = indexOf(FLOAT_COOKIE_BIG_ENDIAN, buffer)) != -1) {
051                                    bigEndian = true;
052                            }
053                            else if ((index = indexOf(FLOAT_COOKIE_LITTLE_ENDIAN, buffer))
054                                            != -1) {
055                                    bigEndian = false;
056                            }
057                            else {
058                                    throw new IOException("Invalid RRD file");
059                            }
060    
061                            switch (index) {
062    
063                                    case 12:
064                                            alignment = 4;
065                                            break;
066    
067                                    case 16:
068                                            alignment = 8;
069                                            break;
070    
071                                    default :
072                                            throw new RuntimeException("Unsupported architecture");
073                            }
074                    }
075                    else {                          // Default to data formats for this hardware architecture
076                    }
077    
078                    ras.seek(0);    // Reset file pointer to start of file
079            }
080    
081            private int indexOf(byte[] pattern, byte[] array) {
082                    return (new String(array)).indexOf(new String(pattern));
083            }
084    
085            boolean isBigEndian() {
086                    return bigEndian;
087            }
088    
089            int getAlignment() {
090                    return alignment;
091            }
092    
093            double readDouble() throws IOException {
094    
095                    //double value;
096                    byte[] tx = new byte[8];
097    
098                    ras.read(buffer, 0, 8);
099    
100                    if (bigEndian) {
101                            tx = buffer;
102                    }
103                    else {
104                            for (int i = 0; i < 8; i++) {
105                                    tx[7 - i] = buffer[i];
106                            }
107                    }
108    
109                    DataInputStream reverseDis =
110                                    new DataInputStream(new ByteArrayInputStream(tx));
111    
112                    return reverseDis.readDouble();
113            }
114    
115            int readInt() throws IOException {
116                    return readInt(false);
117            }
118    
119            int readInt(boolean dump) throws IOException {
120    
121                    ras.read(buffer, 0, 4);
122    
123                    int value;
124    
125                    if (bigEndian) {
126                            value = (0xFF & buffer[3]) | ((0xFF & buffer[2]) << 8)
127                                            | ((0xFF & buffer[1]) << 16) | ((0xFF & buffer[0]) << 24);
128                    }
129                    else {
130                            value = (0xFF & buffer[0]) | ((0xFF & buffer[1]) << 8)
131                                            | ((0xFF & buffer[2]) << 16) | ((0xFF & buffer[3]) << 24);
132                    }
133    
134                    return value;
135            }
136    
137            String readString(int maxLength) throws IOException {
138    
139                    ras.read(buffer, 0, maxLength);
140    
141                    return new String(buffer, 0, maxLength).trim();
142            }
143    
144            void skipBytes(int n) throws IOException {
145                    ras.skipBytes(n);
146            }
147    
148            int align(int boundary) throws IOException {
149    
150                    int skip = (int) (boundary - (ras.getFilePointer() % boundary)) % boundary;
151    
152                    if (skip != 0) {
153                            ras.skipBytes(skip);
154                    }
155    
156                    return skip;
157            }
158    
159            int align() throws IOException {
160                    return align(alignment);
161            }
162    
163            long info() throws IOException {
164                    return ras.getFilePointer();
165            }
166    
167            long getFilePointer() throws IOException {
168                    return ras.getFilePointer();
169            }
170    
171            void close() throws IOException {
172                    ras.close();
173            }
174    }