View Javadoc

1   /***
2    * Created by IntelliJ IDEA.
3    * User: gareth
4    * Date: Sep 11, 2003
5    * Time: 6:43:19 PM
6    */
7   package com.tapina.robe.swi;
8   
9   import com.tapina.robe.runtime.*;
10  import com.tapina.robe.swi.msgtrans.MessageFile;
11  
12  import java.lang.reflect.Method;
13  import java.util.Map;
14  import java.util.HashMap;
15  import java.util.logging.Level;
16  import java.io.IOException;
17  
18  public final class MessageTrans extends SWIHandler {
19      private static MessageTrans ourInstance;
20  
21      public synchronized static MessageTrans getInstance() {
22          if (ourInstance == null) {
23              ourInstance = new MessageTrans();
24          }
25          return ourInstance;
26      }
27  
28      private MessageTrans() {
29      }
30  
31      public static int getBase() {
32          return 0x41500;
33      }
34  
35      private static final String[] methodNames = new String[] {
36          "FileInfo", "OpenFile", "Lookup", "", "", "", "", "", // 0x41500
37          "", "", "", "", "", "", "", "", // 0x41508
38          "", "", "", "", "", "", "", "", // 0x41510
39          "", "", "", "", "", "", "", "", // 0x41518
40          "", "", "", "", "", "", "", "", // 0x41520
41          "", "", "", "", "", "", "", "", // 0x41528
42          "", "", "", "", "", "", "", "", // 0x41530
43          "", "", "", "", "", "", "", "" // 0x41538
44      };
45  
46      public static Method getMethod(Integer offset) throws NoSuchMethodException {
47          return getMethod(methodNames[offset.intValue()]);
48      }
49  
50      private static final Method getMethod(String name) throws NoSuchMethodException {
51          return MessageTrans.class.getMethod(name, METHOD_PARAMETERS);
52      }
53  
54      private static final Map messages = new HashMap(5);
55  
56      /***
57       * Returns information about the size required to hold a message file before MessageTrans_OpenFile used.
58       * Entry:
59       * => R1 = pointer to filename
60       * Exit:
61       * <= R0 = bit 0 set if held in memory
62       * R2 = size of buffer needed
63       * @param env
64       */
65      public void FileInfo(Environment env) {
66          final int[] R = env.getCpu().R;
67  //        final String filename = env.getMemoryMap().loadString0(R[1]);
68          R[0] = 0;
69          R[2] = 4; // Arbitrary small value because we don't need space allocating but zero may cause problems.
70      }
71  
72      /***
73       * This SWI opens a message-file. If R2 = 0, then the data-structure in R0 and the filename in R1 both must
74       * be in the RMA.
75       * Entry:
76       * => R0 = pointer to 4-word data structure
77       *    R1 = pointer to filename
78       *    R2 = pointer to buffer for file data, or 0 to use RMA
79       * @param env
80       */
81      public void OpenFile(Environment env) {
82          final int[] R = env.getCpu().R;
83          final MemoryMap memoryMap = env.getMemoryMap();
84          final int handle = openFile(memoryMap.getString0(R[1])).getHandle();
85          memoryMap.storeWord(R[0], handle);
86      }
87  
88      public MessageFile openFile(String filename) {
89          final MessageFile file;
90          try {
91              file = new MessageFile(FilenameUtils.acornToNative(filename));
92              messages.put(file.getHandleObject(), file);
93              return file;
94          } catch (IOException e) {
95              log.log(Level.WARNING, "Unable to open messages: ", e);
96              throw new SWIError(0, e);
97          }
98      }
99  
100     /***
101      * This SWI looks up the token on the message file. If R2 = 0 on entry, you'll get a pointer to a read-only string,
102      * and no parameter substitution will be done, also the string will be terminated by 10, and not 0. If R2 != 0, %0
103      * to %3 in the string will be replaced by the strings in R4 to R7. Prior to this call, you must have called
104      * MessageTrans_OpenFile .
105      * If the token is not found in the message file specified, it will be searched for in the global message file.
106      * If R2 = 0 on entry and the file is not stored in your own workspace, then the pointer will become invalid after
107      * Service_MessageFileClosed is issued - your application must trap this service call so it can re-read pointers.
108      * Entry:
109      * => R0 = pointer to 4-word data structure, or 0 for global messages
110      * R1 = pointer to Token
111      * R2 = pointer to buffer
112      * R3 = buffer size
113      * R4 = pointer to parameter 0, or 0 if none
114      * R5 = pointer to parameter 1, or 0 if none
115      * R6 = pointer to parameter 2, or 0 if none
116      * R7 = pointer to parameter 3, or 0 if none
117      * Exit:
118      * <= R1 = pointer to token-terminator
119      * R2 = result string
120      * R3 = size of result
121      * @param env
122      */
123     public void Lookup(Environment env) {
124         final int[] R = env.getCpu().R;
125         final MemoryMap memoryMap = env.getMemoryMap();
126         final int handle = memoryMap.getWord(R[0]);
127         final MessageFile file = (MessageFile) messages.get(new Integer(handle));
128         if (file == null) {
129             throw new SWIError(0, "Messages not found");
130         }
131         final String token;
132         if (R[2] != 0) {
133             token = memoryMap.getString0(R[1]);
134         } else {
135             token = memoryMap.getString0_10_13(R[1]);
136         }
137         final int buffer = R[2];
138         final int bufferSize = R[3];
139         final String[] parameters = new String[4];
140         if (R[2] != 0) {
141             for (int i = 0; i < 4; i++) {
142                 parameters[i] = R[4 + i] == 0? null : memoryMap.getString0(R[4 + i]);
143             }
144         }
145         String result = lookup(file, token, parameters);
146         R[1] += token.length();
147         if (buffer == 0) {
148             // TODO: Fix memory leak here
149             final RawDataBlock resultDataBlock = memoryMap.createSystemDataBlock(result);
150             R[2] = resultDataBlock.getAddress();
151         } else {
152             if (result.length() > bufferSize - 1) {
153                 result = result.substring(0, bufferSize - 1);
154             }
155             memoryMap.storeString0(buffer, result);
156         }
157         R[3] = result.length() + 1;
158     }
159 
160     public String lookup(MessageFile file, String token, String[] parameters) {
161         final int defaultValueIndex = token.indexOf(':') + 1;
162         for (int i = 0; i < parameters.length; i++) {
163             if (parameters[i] != null) {
164                 log.warning("Parameter " + i + " ignored: " + parameters[i]);
165             }
166         }
167         final String value;
168         if (defaultValueIndex > 0) {
169             value = file.lookup(token.substring(0, defaultValueIndex - 1), token.substring(defaultValueIndex));
170         } else {
171             value = file.lookup(token, "");
172         }
173         return value;
174     }
175 
176 }
177