Source code: com/flexstor/remote/resourcefork/ntfs/NtfsMacBinaryDecoder.java
1 /*
2 * NtfsMacBinaryDecoder.java
3 *
4 * Copyright $Date: 2003/08/11 02:22:46 $ FLEXSTOR.net Inc.
5 *
6 * This work is licensed for use and distribution under license terms found at
7 * http://www.flexstor.org/license.html
8 *
9 */
10
11 package com.flexstor.remote.resourcefork.ntfs;
12
13 import java.io.ByteArrayInputStream;
14 import java.io.File;
15 import java.io.IOException;
16 import java.io.RandomAccessFile;
17
18 import com.flexstor.common.io.MacBinaryAccessFile;
19
20 public class NtfsMacBinaryDecoder
21 {
22 public static final String AFP_RESOURCE = ":AFP_Resource";
23 public static final String AFP_AFPINFO = ":AFP_AfpInfo";
24 public static final String COMMENTS = ":Comments";
25 public static final String FXINFO = "???"; // Not available
26 public static final String MACBINARY_EXT = ".bin";
27
28 private int nDataForkLength = 0;
29 private int nResourceForkLength = 0;
30
31 public static void main( String[] args )
32 {
33 NtfsMacBinaryDecoder mb = new NtfsMacBinaryDecoder();
34
35 String sInFile = args[0];
36 String sDestination = null;
37
38 try
39 {
40 sDestination = args[1];
41 }
42 catch ( ArrayIndexOutOfBoundsException aioobe )
43 {
44 sDestination = sInFile.substring( 0, sInFile.lastIndexOf( java.io.File.separator ) );
45 }
46
47 try
48 {
49 if ( (new File(sInFile)).exists() == false )
50 return;
51
52 mb.decodeMacBinary( sInFile, sDestination );
53 }
54 catch( IOException ioe )
55 {
56 ioe.printStackTrace();
57 }
58 }
59
60 public void decodeMacBinary( String sInFile, String sDestination )
61 throws IOException
62 {
63 MacBinaryAccessFile mbFile = null;
64 try
65 {
66 // Open a RandomAccess to the MacBinary
67 mbFile = new MacBinaryAccessFile( sInFile, "r" );
68
69 // Get the name of the file
70 //String sOutFile = getFileInformation( mbFile );
71 String sOutFile = (new File(sInFile)).getName();
72 sOutFile = sOutFile.substring( 0, sOutFile.lastIndexOf(".") );
73
74 if ( sDestination.endsWith( java.io.File.separator ) == false )
75 sDestination += java.io.File.separator;
76 sDestination += sOutFile;
77
78 getDataFork( mbFile, sDestination );
79 getResourceFork( mbFile, sDestination + AFP_RESOURCE );
80 getComments( mbFile, sDestination + COMMENTS );
81 getFinderInfo( mbFile, sDestination + AFP_AFPINFO );
82 //getFXInfo( mbFile, sDestination + FXINFO ); Not used yet.
83 }
84 finally
85 {
86 if ( mbFile != null )
87 mbFile.close();
88 }
89 }
90
91 private String getFileInformation( MacBinaryAccessFile mbFile )
92 throws IOException
93 {
94 // Get the filename length
95 return mbFile.getFileName();
96 }
97
98 private void getDataFork( MacBinaryAccessFile mbFile, String sOutFile )
99 throws IOException
100 {
101 mbFile.getDataFork( sOutFile );
102 }
103
104 private void getResourceFork( MacBinaryAccessFile mbFile, String sOutFile )
105 throws IOException
106 {
107 RandomAccessFile resourceFork = null;
108 ByteArrayInputStream baInputStream = null;
109 try
110 {
111 baInputStream = mbFile.getResourceFork();
112 resourceFork = new RandomAccessFile( sOutFile, "rw" );
113
114 if ( baInputStream != null )
115 {
116 // Write data fork
117 byte[] ba = new byte[MacBinaryAccessFile.BUFFER_SIZE];
118 int length = 0;
119 while( (length = baInputStream.read(ba)) != -1 )
120 resourceFork.write( ba, 0, length );
121 }
122 }
123 finally
124 {
125 if ( baInputStream != null )
126 baInputStream.close();
127
128 if ( resourceFork != null )
129 resourceFork.close();
130 }
131 }
132
133 private void getComments( MacBinaryAccessFile mbFile, String sOutFile )
134 throws IOException
135 {
136 RandomAccessFile comments = null;
137 ByteArrayInputStream baInputStream = null;
138 try
139 {
140 baInputStream = mbFile.getComment();
141 comments = new RandomAccessFile( sOutFile, "rw" );
142
143 if ( baInputStream != null )
144 {
145 // Write data fork
146 byte[] ba = new byte[MacBinaryAccessFile.BUFFER_SIZE];
147 int length = 0;
148 while( (length = baInputStream.read(ba)) != -1 )
149 comments.write( ba, 0, length );
150 }
151 }
152 finally
153 {
154 if ( baInputStream != null )
155 baInputStream.close();
156
157 if ( comments != null )
158 comments.close();
159 }
160 }
161
162 /*
163 * Offset typedef struct _AfpInfo
164 * {
165 * 0 DWORD afpi_Signature; // Must be *(PDWORD)"AFP"
166 * 4 LONG afpi_Version; // Must be 0x00010000
167 * 8 DWORD afpi_Reserved1;
168 * 12 DWORD afpi_BackupTime; // Backup time for the file/dir
169 * 16 FINDERINFO afpi_FinderInfo; // Finder Info (32 bytes)
170 * 48 PRODOSINFO afpi_ProDosInfo; // ProDos Info (6 bytes) #
171 * 54 BYTE afpi_Reserved2[6];
172 * } AFPINFO, *PAFPINFO;
173 *
174 * #define FINDER_INFO_SIZE 32
175 * typedef struct
176 * {
177 * 16 BYTE fd_Type[4];
178 * 20 BYTE fd_Creator[4];
179 * 24 BYTE fd_Attr1; // Bits 8-15
180 * 25 BYTE fd_Attr2; // Bits 0-7
181 * 26 BYTE fd_Location[4];
182 * 30 BYTE fd_FDWindow[2];
183 * 32 BYTE fd_OtherStuff[16];
184 * } FINDERINFO, *PFINDERINFO;
185 *
186 * #define PRODOS_INFO_SIZE 6
187 * typedef struct
188 * {
189 * 48 BYTE pd_FileType[2];
190 * 50 BYTE pd_AuxType[4];
191 * } PRODOSINFO, *PPRODOSINFO;
192 */
193 private void getFinderInfo( MacBinaryAccessFile mbFile, String sOutFile )
194 throws IOException
195 {
196 RandomAccessFile afpInfo = null;
197 try
198 {
199 // Open AFP_ApfInfo stream
200 afpInfo = new RandomAccessFile( sOutFile, "rw" );
201
202 // Go to offset for type in AFP_AfpInfo
203 afpInfo.seek(0);
204
205 // 0 - DWORD - afpi_Signature; // Must be 0x00504641 *(PDWORD)"AFP"
206 afpInfo.writeInt( Integer.parseInt( "41465000", 16 ) );
207
208 // 4 - LONG - afpi_Version; // Must be 0x00010000
209 afpInfo.writeInt( Integer.parseInt( "00000100", 16 ) );
210
211 // 8 - DWORD - afpi_Reserved1; // Must be 0 if creating the stream
212 afpInfo.writeInt( Integer.parseInt( "00000000", 16 ) );
213
214 // 12 - DWORD - afpi_BackupTime; // Should be 0x80000000 (never been backed up) if creating the file.
215 afpInfo.writeInt( Integer.parseInt( "00000080", 16 ) );
216
217 // 16 - BYTE - fd_Type[4];
218 afpInfo.write( mbFile.getFileType() );
219
220 // 20 - BYTE - fd_Creator[4];
221 afpInfo.write( mbFile.getFileCreator() );
222
223 // 24 - BYTE - fd_Attr1; // Bits 8-15
224 // 073 - Byte - original Finder flags
225 // AFP_AfpInfo MacBinary File
226 // Bit 15 - isAlias - Bit 7
227 // Bit 14 - isInvisible - Bit 6
228 // Bit 13 - hasBundle - Bit 5
229 // Bit 12 - nameLocked - Bit 4
230 // Bit 11 - isStationery - Bit 3
231 // Bit 10 - hasCustomIcon - Bit 2
232 // Bit 9 - reserved - Bit 1
233 // Bit 8 - hasBeenInited - Bit 0
234 afpInfo.writeByte( mbFile.getFirstByteOfFinderFlags() );
235
236 // 25 - BYTE - fd_Attr2; // Bits 0-7
237 // 101 - Byte - Finder Flags, bits 0-7. (Bits 8-15 are already in byte 73)
238 // AFP_AfpInfo MacBinary File
239 // Bit 7 - hasNoInits - Bit 7
240 // Bit 6 - isShared - Bit 6
241 // Bit 5 - requiresSwitchLaunch - Bit 5
242 // Bit 4 - ColorReserved - Bit 4
243 // Bit 1-3 - color - Bit 1-3
244 // Bit 0 - isOnDesk - Bit 0
245 afpInfo.writeByte( mbFile.getSecondByteOfFinderFlags() );
246
247 // 26 - BYTE - fd_Location[4];
248 afpInfo.write( mbFile.getVerticalPosition() );
249 afpInfo.write( mbFile.getHorizontalPosition() );
250
251 // 30 - BYTE - fd_FDWindow[2];
252 afpInfo.write( mbFile.getFolderId() );
253
254 // 32 - BYTE - fd_OtherStuff[16];
255 afpInfo.writeLong( 0 );
256 afpInfo.writeLong( 0 );
257
258 // 48 - BYTE - pd_FileType[2];
259 afpInfo.writeShort( 0 );
260
261 // 50 - BYTE - pd_AuxType[4];
262 afpInfo.writeInt( 0 );
263
264 // 54 - BYTE - afpi_Reserved2[6];
265 afpInfo.writeShort( 0 );
266 afpInfo.writeInt( 0 );
267 }
268 finally
269 {
270 if ( afpInfo != null )
271 afpInfo.close();
272 }
273 }
274
275 private void getFXInfo( MacBinaryAccessFile mbFile, String sOutFile )
276 throws IOException
277 {
278 RandomAccessFile fxInfo = null;
279 try
280 {
281 fxInfo = new RandomAccessFile( sOutFile, "rw" );
282
283 // 106 - Byte - script of file name (from the fdScript field of an fxInfo record)
284 // Information not available
285
286 // 107 - Byte - extended Finder flags (from the fdXFlags field of an fxInfo record)
287 // Information not available
288 }
289 finally
290 {
291 if ( fxInfo != null )
292 fxInfo.close();
293 }
294 }
295 }