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 }