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    }