OSDN Git Service

Add new source files
[armadillo/armadillo1.git] / src / jp / sfjp / armadillo / archive / cab / DumpCabHeader.java
1 package jp.sfjp.armadillo.archive.cab;
2
3 import java.io.*;
4 import java.nio.*;
5 import java.nio.channels.*;
6 import java.util.*;
7 import jp.sfjp.armadillo.archive.*;
8 import jp.sfjp.armadillo.time.*;
9
10 /**
11  * Dump CAB archive header.
12  */
13 public final class DumpCabHeader extends DumpArchiveHeader {
14
15     // signature 'MSCF'
16     static final int SIGNATURE = 0x4D534346;
17
18     private static final FTime FTIME = new FTime();
19     private static final String fmt0 = "  -- %s[%d] --%n";
20     private static final String fmt1 = "  * %s = %s%n";
21     private static final String fmt2 = "  %1$-16s = [0x%2$08X] ( %2$d )%n";
22
23     private static final int BUFFER_SIZE = 1024;
24
25     private final ByteBuffer buffer;
26     private short[] folderCompressType;
27
28     public DumpCabHeader() {
29         this.buffer = ByteBuffer.allocate(BUFFER_SIZE).order(ByteOrder.LITTLE_ENDIAN);
30     }
31
32     @SuppressWarnings("unused")
33     @Override
34     public void dump(InputStream is, PrintWriter out) throws IOException {
35         // Cabinet File header
36         final int signature; // cabinet file signature
37         final int reserved1; // reserved
38         final int cbCabinet; // size of this cabinet file in bytes
39         final int reserved2; // reserved
40         final int coffFiles; // offset of the first CFFILE entry
41         final int reserved3; // reserved
42         final byte versionMinor; // cabinet file format version, minor
43         final byte versionMajor; // cabinet file format version, major
44         final short cFolders; // number of CFFOLDER entries in this cabinet
45         final short cFiles; // number of CFFILE entries in this cabinet
46         final short flags; // cabinet file option indicators
47         final short setID; // must be the same for all cabinets in a set
48         final short iCabinet;// number of this cabinet file in a set
49         buffer.clear();
50         buffer.limit(36);
51         Channels.newChannel(is).read(buffer);
52         if (buffer.position() == 0)
53             throw new CabException("reading archive header, but position is zero");
54         buffer.rewind();
55         buffer.order(ByteOrder.BIG_ENDIAN);
56         signature = buffer.getInt();
57         if (signature != SIGNATURE)
58             throw new CabException("bad signature: 0x%X", signature);
59         buffer.order(ByteOrder.LITTLE_ENDIAN);
60         reserved1 = buffer.getInt();
61         cbCabinet = buffer.getInt();
62         reserved2 = buffer.getInt();
63         coffFiles = buffer.getInt();
64         reserved3 = buffer.getInt();
65         versionMinor = buffer.get();
66         versionMajor = buffer.get();
67         cFolders = buffer.getShort();
68         cFiles = buffer.getShort();
69         flags = buffer.getShort();
70         setID = buffer.getShort();
71         iCabinet = buffer.getShort();
72         printHeaderName(out, "Cabinet File header");
73         out.printf(fmt2, "signature", signature);
74         out.printf(fmt2, "reserved1", reserved1);
75         out.printf(fmt2, "cbCabinet", cbCabinet);
76         out.printf(fmt2, "reserved2", reserved2);
77         out.printf(fmt2, "coffFiles", coffFiles);
78         out.printf(fmt2, "reserved3", reserved3);
79         out.printf(fmt2, "versionMinor", versionMinor);
80         out.printf(fmt2, "versionMajor", versionMajor);
81         out.printf(fmt2, "cFolders", cFolders);
82         out.printf(fmt2, "cFiles", cFiles);
83         out.printf(fmt2, "flags", flags);
84         out.printf(fmt2, "setID", setID);
85         out.printf(fmt2, "iCabinet", iCabinet);
86         if (iCabinet != 0) {
87             warn(out, "iCabinet not supported: 0x%d", iCabinet);
88             return;
89         }
90         // array size of folderCompressType
91         folderCompressType = new short[cFolders];
92         // read CFFOLDERs
93         printHeaderName(out, "CFFOLDER headers");
94         int cfdatacount = 0;
95         for (int i = 0; i < cFolders; i++) {
96             // CFFOLDER header
97             final int coffCabStart; // offset of the first CFDATA block in this folder
98             final short cCFData; // number of CFDATA blocks in this folder
99             final short typeCompress; // compression type indicator
100             final byte[] abReserve; // (optional) per-folder reserved area
101             buffer.clear();
102             buffer.limit(8);
103             Channels.newChannel(is).read(buffer);
104             if (buffer.position() == 0) {
105                 warn(out, "reading CFFOLDER header, but position is zero");
106                 return;
107             }
108             buffer.rewind();
109             coffCabStart = buffer.getInt();
110             cCFData = buffer.getShort();
111             typeCompress = buffer.getShort();
112             // ignore optional data
113             abReserve = new byte[0];
114             folderCompressType[i] = typeCompress;
115             out.printf(fmt0, "CFFOLDER", i);
116             out.printf(fmt2, "coffCabStart", coffCabStart);
117             out.printf(fmt2, "cCFData", cCFData);
118             out.printf(fmt2, "typeCompress", typeCompress);
119             //            out.printf(fmt2, "abReserve", abReserve);
120             cfdatacount += cCFData;
121         }
122         // read CFFILEs
123         printHeaderName(out, "CFFILE headers");
124         for (int i = 0; i < cFiles; i++) {
125             // CFFILE header
126             final int cbFile; // uncompressed size of this file in bytes
127             final int uoffFolderStart; // uncompressed offset of this file in the folder
128             final short iFolder; // index into the CFFOLDER area
129             final short date; // date stamp for this file
130             final short time; // time stamp for this file
131             final short attribs; // attribute flags for this file
132             final byte[] szName; // name of this file
133             buffer.clear();
134             buffer.limit(16);
135             Channels.newChannel(is).read(buffer);
136             if (buffer.position() == 0)
137                 throw new CabException("reading CFFILE header, but position is zero");
138             buffer.rewind();
139             cbFile = buffer.getInt();
140             uoffFolderStart = buffer.getInt();
141             iFolder = buffer.getShort();
142             date = buffer.getShort();
143             time = buffer.getShort();
144             attribs = buffer.getShort();
145             szName = readName(is, 256);
146             final String name = new String(szName);
147             out.printf(fmt0, "CFFILE", i);
148             out.printf(fmt1, "name", name);
149             out.printf(fmt1, "mtime as date", toDate(date, time));
150             out.printf(fmt2, "cbFile", cbFile);
151             out.printf(fmt2, "uoffFolderStart", uoffFolderStart);
152             out.printf(fmt2, "iFolder", iFolder);
153             out.printf(fmt2, "date", date);
154             out.printf(fmt2, "time", time);
155             out.printf(fmt2, "attribs", attribs);
156             out.printf(fmt2, "szName.length", szName.length);
157         }
158         // read CFDATAs
159         printHeaderName(out, "CFDATA headers");
160         for (int i = 0; i < cfdatacount; i++) {
161             // CFDATA header
162             final int csum; // checksum of this CFDATA entry
163             final short cbData; // number of compressed bytes in this block
164             final short cbUncomp; // number of uncompressed bytes in this block
165             final byte[] abReserve; // (optional) per-datablock reserved area
166             final byte[] ab; // compressed data bytes
167             buffer.clear();
168             buffer.limit(8);
169             Channels.newChannel(is).read(buffer);
170             if (buffer.position() < 8)
171                 break;
172             buffer.rewind();
173             csum = buffer.getInt();
174             cbData = buffer.getShort();
175             cbUncomp = buffer.getShort();
176             out.printf(fmt0, "CFDATA", i);
177             out.printf(fmt2, "csum", csum);
178             out.printf(fmt2, "cbData", cbData);
179             out.printf(fmt2, "cbUncomp", cbUncomp);
180             int skipSize = cbData;
181             while (skipSize > 0)
182                 skipSize -= is.skip(skipSize);
183         }
184         printEnd(out, "CAB", 0);
185     }
186
187     static Date toDate(int mdate, int mtime) {
188         final int ftime = (mdate << 16) | mtime & 0xFFFF;
189         return new Date(FTIME.toMilliseconds(ftime));
190     }
191
192     private byte[] readName(InputStream is, int limit) throws IOException {
193         byte[] bytes = new byte[limit];
194         int readSize = 0;
195         for (int i = 0; i < limit; i++) {
196             int b = is.read();
197             if (b <= 0)
198                 break;
199             bytes[i] = (byte)(b & 0xFF);
200             ++readSize;
201         }
202         if (readSize < limit)
203             return Arrays.copyOf(bytes, readSize);
204         else
205             return bytes;
206     }
207
208 }