View Javadoc

1   /*
2    * $Id: DefaultZObject.java,v 1.3 2005/10/18 17:31:06 weiju Exp $
3    * 
4    * Created on 25.09.2005
5    * Copyright 2005 by Wei-ju Wu
6    *
7    * This file is part of The Z-machine Preservation Project (ZMPP).
8    *
9    * ZMPP is free software; you can redistribute it and/or modify
10   * it under the terms of the GNU General Public License as published by
11   * the Free Software Foundation; either version 2 of the License, or
12   * (at your option) any later version.
13   *
14   * ZMPP is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Public License for more details.
18   *
19   * You should have received a copy of the GNU General Public License
20   * along with ZMPP; if not, write to the Free Software
21   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22   */
23  package org.zmpp.vm;
24  
25  import org.zmpp.base.MemoryAccess;
26  
27  /***
28   * This is the default implementation of a ZObject.
29   * 
30   * @author Wei-ju Wu
31   * @version 1.0
32   */
33  public class DefaultZObject implements ZObject {
34  
35    /***
36     * The property table is defined in the object's context
37     * to make it dependent on a specific instance.
38     */
39    private class PropertyTable {
40      
41      /***
42       * Returns this property table's description string address.
43       * 
44       * @return the address of the description
45       */
46      public int getDescriptionAddress() {
47        
48        return getPropertyTableAddress() + 1;
49      }
50      
51      /***
52       * Returns the start address of the actual property entries.
53       * 
54       * @return the property entries' start address
55       */
56      private int getPropertyEntriesStart() {
57        
58        return getPropertyTableAddress() + getDescriptionHeaderSize();
59      }
60      
61      /***
62       * Returns the size of the description header in bytes that is,
63       * the size byte plus the description string size.
64       *  
65       * @return the size of the description header 
66       */
67      private int getDescriptionHeaderSize() {
68        
69        int startAddr = getPropertyTableAddress();
70        return memaccess.readUnsignedByte(startAddr) * 2 + 1;
71      }
72      
73      /***
74       * Reads the property size byte at the given address.
75       * 
76       * @param address the address of a property size byte
77       * @return the size of the property entry in bytes
78       */
79      private int getPropertySizeAtAddress(int address) {
80        
81        return memaccess.readUnsignedByte(address) / 32 + 1;
82      }
83      
84      /***
85       * Returns the address of the specified property.
86       * 
87       * @param index the property index
88       * @return the address of the specified property
89       */
90      private int getPropertyAddress(int index) {
91        
92        int addr = getPropertyEntriesStart();
93        int size = 0;
94        
95        // iterate over the previous entries and
96        // skip over the entries        
97        for (int i = 0; i < index; i++) {
98            
99          size = getPropertySizeAtAddress(addr);
100         addr += (size + 1);
101       }
102       return addr;
103     }
104     
105     /***
106      * Returns the number of properties in this property table.
107      * 
108      * @return the number of properties
109      */
110     public int getNumProperties() {
111       
112       int row = 0;
113       while (memaccess.readUnsignedByte(getPropertyAddress(row)) > 0) {
114         
115         row++;
116       }
117       return row;
118     }
119     
120     /***
121      * Returns the size of the property in bytes.
122      * 
123      * @param index the property index
124      * @return the size of the specified property in bytes
125      */
126     public int getSize(int index) {
127       
128       return getPropertySizeAtAddress(getPropertyAddress(index));
129     }
130     
131     /***
132      * Returns the property at the specified row and column position.
133      * 
134      * @param index the property index
135      * @param bytenum the byte number
136      * @return the unsigned byte value at the specified position of the
137      * property
138      */
139     public byte getPropertyByte(int index, int bytenum) {
140       
141       int addr = getPropertyAddress(index);
142       return memaccess.readByte(addr + 1 + bytenum);
143     }
144     
145     /***
146      * Writes a value to the specified property byte.
147      * 
148      * @param index the property index
149      * @param bytenum the byte number
150      * @param value the value to set
151      */
152     public void setPropertyByte(int index, int bytenum, byte value) {
153       
154       int addr = getPropertyAddress(index);
155       memaccess.writeByte(addr + 1 + bytenum, value);
156     }
157 
158     /***
159      * Returns the property number at the specified table index.
160      * 
161      * @param index the property table index
162      * @return the property number
163      */
164     public short getPropertyNum(int index) {
165       
166       int addr = getPropertyAddress(index);
167       int sizeByte = memaccess.readUnsignedByte(addr);
168       return (short) (sizeByte - 32 * (getPropertySizeAtAddress(addr) - 1));
169     }
170     
171     /***
172      * Returns the property table index for the specified property number.
173      * 
174      * @param propertyNum the property number
175      * @return the table index
176      */
177     public short getPropertyIndex(int propertyNum) {
178       
179       for (int i = 0; i < getNumProperties(); i++) {
180         
181         if (getPropertyNum(i) == propertyNum) return (short) i;
182       }
183       return -1;
184     }
185     
186     /***
187      * Returns the size of this object's property table in bytes.
188      * 
189      * @return the size of the property table in bytes
190      */
191     public int getDataLength() {
192       
193       int size = getDescriptionHeaderSize();
194       
195       for (int i = 0; i < getNumProperties(); i++) {
196         
197         size += (getSize(i) + 1);
198       }
199       return size;
200     }
201   }
202   
203   /***
204    * The memory access object.
205    */
206   private MemoryAccess memaccess;
207   
208   /***
209    * The address of this Z-object.
210    */
211   int address;
212   
213   /***
214    * This object's properties.
215    */
216   private PropertyTable propertyTable;
217   
218   /***
219    * Constructor.
220    * 
221    * @param address the start address of the object
222    */
223   public DefaultZObject(MemoryAccess memaccess, int address) {
224     
225     this.memaccess = memaccess;
226     this.address = address;
227     this.propertyTable = new PropertyTable();
228   }
229   
230   /***
231    * The attribute flags, a 32 bit unsigned value as a long.
232    * 
233    * @return the attribute flags
234    */
235   private long getAttributeFlags() {
236     
237     return memaccess.readUnsigned32(address);
238   }
239   
240   /***
241    * Sets a 32 bit unsigned value to the attribute flags.
242    * 
243    * @param flags32 the flags value
244    */
245   private void setAttributeFlags(long flags32) {
246     
247     memaccess.writeUnsigned32(address, flags32);
248   }
249 
250   /***
251    * {@inheritDoc}
252    */
253   public boolean isAttributeSet(int attributeNum) {
254     
255     long bitmask = 0x0000000080000000l >> attributeNum;
256     return (getAttributeFlags() & bitmask) != 0;
257   }
258 
259   /***
260    * {@inheritDoc}
261    */
262   public void setAttribute(int attributeNum) {
263     
264     long bitmask = 0x0000000080000000l >> attributeNum;
265     long value = (getAttributeFlags() | bitmask);
266     setAttributeFlags(value);
267   }
268 
269   /***
270    * {@inheritDoc}
271    */
272   public void clearAttribute(int attributeNum) {
273     
274     long bitmask = (long) 0xffffffff7fffffffl >> attributeNum;
275     long value = (getAttributeFlags() & bitmask);
276     setAttributeFlags(value);      
277   }
278 
279   /***
280    * {@inheritDoc}
281    */
282   public int getParent() {
283     
284     return memaccess.readUnsignedByte(address + 4);
285   }
286   
287   /***
288    * {@inheritDoc}
289    */
290   public void setParent(int parent) {
291     
292     memaccess.writeUnsignedByte(address + 4, (short) (parent & 0xff));
293   }
294   
295   /***
296    * {@inheritDoc}
297    */
298   public int getSibling() {
299     
300     return memaccess.readUnsignedByte(address + 5);
301   }
302   
303   /***
304    * {@inheritDoc}
305    */
306   public void setSibling(int sibling) {
307     
308     memaccess.writeUnsignedByte(address + 5, (short) (sibling & 0xff));
309   }
310   
311   /***
312    * {@inheritDoc}
313    */
314   public int getChild() {
315     
316     return memaccess.readUnsignedByte(address + 6);
317   }
318   
319   /***
320    * {@inheritDoc}
321    */
322   public void setChild(int child) {
323     
324     memaccess.writeUnsignedByte(address + 6, (short) (child & 0xff));
325   }
326  
327   /***
328    * {@inheritDoc}
329    */
330   public int getPropertyTableAddress() {
331     
332     return memaccess.readUnsignedShort(address + 7);
333   }
334 
335   /***
336    * {@inheritDoc}
337    */
338   public int getPropertiesDescriptionAddress() {
339     
340     return propertyTable.getDescriptionAddress();
341   }
342 
343   /***
344    * {@inheritDoc}
345    */
346   public int getNumProperties() {
347     
348     return propertyTable.getNumProperties();
349   }
350 
351   /***
352    * {@inheritDoc}
353    */
354   public int getPropertySize(int property) {
355     
356     int index = propertyTable.getPropertyIndex(property);
357     return propertyTable.getSize(index);
358   }
359   
360   /***
361    * {@inheritDoc}
362    */
363   public byte getPropertyByte(int property, int bytenum) {
364     
365     int index = propertyTable.getPropertyIndex(property);
366     return propertyTable.getPropertyByte(index, bytenum);
367   }
368 
369   /***
370    * {@inheritDoc}
371    */
372   public int getPropertyAddress(int property) {
373     
374     int index = propertyTable.getPropertyIndex(property);
375     return propertyTable.getPropertyAddress(index) + 1;
376   }
377 
378   /***
379    * {@inheritDoc}
380    */
381   public boolean isPropertyAvailable(int property) {
382     
383     return (propertyTable.getPropertyIndex(property) >= 0);
384   }
385 
386   /***
387    * {@inheritDoc}
388    */
389   public int getNextProperty(int property) {
390     
391     if (property == 0) {
392       
393       return propertyTable.getPropertyNum(0);
394       
395     } else {
396       
397       int index = propertyTable.getPropertyIndex(property);
398       return propertyTable.getPropertyNum(index + 1);
399     }
400   }
401   
402   /***
403    * {@inheritDoc}
404    */
405   public void setPropertyByte(int property, int bytenum, byte value) {
406     
407     int index = propertyTable.getPropertyIndex(property);
408     propertyTable.setPropertyByte(index, bytenum, value);
409   }
410 }