001 /*
002 Copyright (c) 2009 Olivier Chafik, All Rights Reserved
003
004 This file is part of JNAerator (http://jnaerator.googlecode.com/).
005
006 JNAerator is free software: you can redistribute it and/or modify
007 it under the terms of the GNU Lesser General Public License as published by
008 the Free Software Foundation, either version 3 of the License, or
009 (at your option) any later version.
010
011 JNAerator is distributed in the hope that it will be useful,
012 but WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014 GNU Lesser General Public License for more details.
015
016 You should have received a copy of the GNU Lesser General Public License
017 along with JNAerator. If not, see <http://www.gnu.org/licenses/>.
018 */
019 package com.ochafik.lang.jnaerator.runtime;
020
021 import com.sun.jna.Memory;
022 import java.lang.ref.WeakReference;
023 import java.lang.reflect.Field;
024 import java.nio.Buffer;
025
026 import com.sun.jna.Native;
027 import com.sun.jna.Pointer;
028 import java.lang.reflect.Array;
029
030 public abstract class Structure<S extends Structure<S, V, R>, V extends S, R extends S>
031 extends com.sun.jna.Structure
032 implements
033 Comparable<Structure<S, V, R>>,
034 StructureType,
035 StructureTypeDependent
036 {
037 public interface ByReference extends com.sun.jna.Structure.ByReference, StructureTypeDependent {}
038 public interface ByValue extends com.sun.jna.Structure.ByValue, StructureTypeDependent {}
039
040 transient WeakReference<StructureType> dependency;
041 @Override
042 public void setDependency(StructureType type) {
043 this.dependency = type == null ? null : new WeakReference<StructureType>(type);
044 }
045 protected void readDependency() {
046 StructureType dep;
047 if (dependency == null || (dep = dependency.get()) == null)
048 return;
049 dep.read();
050 }
051
052 @Override
053 public void read() {
054 super.read();
055 readDependency();
056 }
057 @Override
058 public void write() {
059 super.write();
060 readDependency();
061 }
062
063 protected <T extends Structure<S, V, R>> T setupClone(T clone, StructureType dependency) {
064 write();
065 clone.useMemory(getPointer());
066 clone.setDependency(this);
067 return clone;
068 }
069
070 //getFieldOffset(String fieldName);
071
072 protected abstract S newInstance();
073 protected abstract V newByValue();
074 protected abstract R newByReference();
075
076 public R byReference() { return setupClone(newByReference(), this); }
077 public V byValue() { return setupClone(newByValue(), this); }
078 public S clone() { return setupClone(newInstance(), this); }
079
080 public static <S extends Structure>
081 S[] newArray(Class<S> structClass, int arrayLength) {
082 try {
083 S first = structClass.newInstance();
084 int sz = first.size();
085 Memory mem = new Memory(arrayLength * sz);
086 first.use(mem);
087 S[] array = (S[])first.castToArray(arrayLength);
088 for (int i = 1; i < arrayLength; i++) {
089 S s = structClass.newInstance();
090 s.use(mem, i * sz);
091 array[i] = s;
092 }
093 return array;
094 } catch (Exception ex) {
095 throw new RuntimeException(ex);
096 }
097 }
098 /**
099 * @deprecated use castToArray instead
100 */
101 @Deprecated
102 @SuppressWarnings("unchecked")
103 @Override
104 public S[] toArray(int size) {
105 return (S[])super.toArray(size);
106 }
107 /**
108 * @deprecated use castToArray instead
109 */
110 @Deprecated
111 public S[] toArray() {
112 return toArray(1);
113 }
114 /**
115 * @deprecated use castToArray instead
116 */
117 @Deprecated
118 @SuppressWarnings("unchecked")
119 public R[] toReferenceArray(int size) {
120 return (R[])byReference().toArray(size);
121 }
122 /**
123 * @deprecated use castToArray instead
124 */
125 @Deprecated
126 @SuppressWarnings("unchecked")
127 public V[] toValueArray(int size) {
128 return (V[])byValue().toArray(size);
129 }
130 /**
131 * @deprecated use castToArray instead
132 */
133 @Deprecated
134 public R[] toReferenceArray() {
135 return toReferenceArray(1);
136 }
137 /**
138 * @deprecated use castToArray instead
139 */
140 @Deprecated
141 public V[] toValueArray() {
142 return toValueArray(1);
143 }
144
145 /**
146 * @deprecated use castToArray instead
147 */
148 @Deprecated
149 @SuppressWarnings("unchecked")
150 @Override
151 public S[] toArray(com.sun.jna.Structure[] array) {
152 return (S[])super.toArray(array);
153 }
154
155 @SuppressWarnings("unchecked")
156 public S[] castToArray(int size) {
157 return (S[])super.toArray(size);
158 }
159 public S[] castToArray() {
160 return castToArray(1);
161 }
162 @SuppressWarnings("unchecked")
163 public R[] castToReferenceArray(int size) {
164 return (R[])byReference().toArray(size);
165 }
166 @SuppressWarnings("unchecked")
167 public V[] castToValueArray(int size) {
168 return (V[])byValue().toArray(size);
169 }
170 public R[] castToReferenceArray() {
171 return castToReferenceArray(1);
172 }
173 public V[] castToValueArray() {
174 return castToValueArray(1);
175 }
176 @SuppressWarnings("unchecked")
177 public S[] castToArray(com.sun.jna.Structure[] array) {
178 return (S[])super.toArray(array);
179 }
180
181
182 @Override
183 protected Integer getBitsAnnotation(Field field) {
184 Bits bits = field.getAnnotation(Bits.class);
185 return bits == null ? null : bits.value();
186 }
187 /** Simply does a memcmp between the two memory blocks of the two structures
188 */
189 @Override
190 public int compareTo(Structure<S, V, R> o) {
191 if (o == this)
192 return 0;
193 if (!(o instanceof Structure<?, ?, ?>))
194 return 1;
195
196 int size = size();
197 int d = size - ((Structure<?, ?, ?>)o).size();
198 if (d != 0)
199 return d;
200
201 Structure<?, ?, ?> s = (Structure<?, ?, ?>)o;
202 if (getPointer().equals(s.getPointer()))
203 return 0;
204
205 write();
206 s.write();
207
208 byte[] bytes1 = getPointer().getByteArray(0, size);
209 byte[] bytes2 = s.getPointer().getByteArray(0, size);
210
211 for (int i = 0; i < size; i++) {
212 byte b1 = bytes1[i], b2 = bytes2[i];
213 if (b1 != b2)
214 return b1 < b2 ? -1 : 1;
215 }
216 return 0;
217 }
218
219 protected <T extends Union<?, ?, ?>> T setupClone(T clone) {
220 write();
221 clone.use(getPointer());
222 return clone;
223 }
224
225 public S use(Pointer m) {
226 return use(m, 0);
227 }
228 public S use(Pointer m, long byteOffset) {
229 useMemory(m, (int)byteOffset);
230 return (S)this;
231 }
232 public S use(Buffer m) {
233 return use(m, 0);
234 }
235 public S use(Buffer b, long byteOffset) {
236 useMemory(Native.getDirectBufferPointer(b), (int)byteOffset);
237 return (S)this;
238 }
239
240 }