1 /*
2  *  JIIC: Java ISO Image Creator. Copyright (C) 2007, Jens Hatlak <hatlak@rbg.informatik.tu-darmstadt.de>
3  *
4  *  This library is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU Lesser General Public
6  *  License as published by the Free Software Foundation; either
7  *  version 2.1 of the License, or (at your option) any later version.
8  *
9  *  This library is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *  Lesser General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Lesser General Public
15  *  License along with this library; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  *
18  */
19 
20 package de.tu_darmstadt.informatik.rbg.hatlak.rockridge.impl;
21 
22 import de.tu_darmstadt.informatik.rbg.hatlak.iso9660.impl.ISO9660DateDataReference;
23 import de.tu_darmstadt.informatik.rbg.hatlak.iso9660.impl.ISO9660ShortDateDataReference;
24 import de.tu_darmstadt.informatik.rbg.hatlak.sabre.impl.BothWordDataReference;
25 import de.tu_darmstadt.informatik.rbg.mhartle.sabre.DataReference;
26 import de.tu_darmstadt.informatik.rbg.mhartle.sabre.Fixup;
27 import de.tu_darmstadt.informatik.rbg.mhartle.sabre.HandlerException;
28 import de.tu_darmstadt.informatik.rbg.mhartle.sabre.StreamHandler;
29 import de.tu_darmstadt.informatik.rbg.mhartle.sabre.impl.ByteArrayDataReference;
30 import de.tu_darmstadt.informatik.rbg.mhartle.sabre.impl.ByteDataReference;
31 
32 public class RRIPFactory extends SUSPFactory {
33 	public static boolean MKISOFS_COMPATIBILITY = true;
34 	public static final int CR_CONTINUES = 1;
35 	public static final int CR_CURRENT = 2;
36 	public static final int CR_PARENT = 4;
37 	public static final int CR_ROOT = 8;
38 	public static final int NM_CONTINUES = 1;
39 	public static final int NM_CURRENT = 2;
40 	public static final int NM_PARENT = 4;
41 	public static final int TF_CREATION = 1;
42 	public static final int TF_MODIFY = 2;
43 	public static final int TF_ACCESS = 4;
44 	public static final int TF_ATTRIBUTES = 8;
45 	public static final int TF_BACKUP = 16;
46 	public static final int TF_EXPIRATION = 32;
47 	public static final int TF_EFFECTIVE = 64;
48 	public static final int TF_LONG_FORM = 128;
49 	public static final int RR_PX_RECORDED = 1;
50 	public static final int RR_PN_RECORDED = 2;
51 	public static final int RR_SL_RECORDED = 4;
52 	public static final int RR_NM_RECORDED = 8;
53 	public static final int RR_CL_RECORDED = 16;
54 	public static final int RR_PL_RECORDED = 32;
55 	public static final int RR_RE_RECORDED = 64;
56 	public static final int RR_TF_RECORDED = 128;
57 	public static final int NM_ENTRY_LENGTH = 5;
58 
RRIPFactory(StreamHandler streamHandler)59 	public RRIPFactory(StreamHandler streamHandler) {
60 		super(streamHandler);
61 	}
62 
doPXEntry(int fileModes, int fileLinks, int uid, int gid, long serialNumber)63 	public void doPXEntry(int fileModes, int fileLinks, int uid, int gid, long serialNumber) throws HandlerException {
64 		streamHandler.startElement(new SystemUseEntryElement("PX", 1));
65 		streamHandler.data(new BothWordDataReference(fileModes));
66 		streamHandler.data(new BothWordDataReference(fileLinks));
67 		streamHandler.data(new BothWordDataReference(uid));
68 		streamHandler.data(new BothWordDataReference(gid));
69 
70 		if (!MKISOFS_COMPATIBILITY) {
71 			// RRIP 1.12 includes the Serial Number field, RRIP 1.09 does not
72 			streamHandler.data(new BothWordDataReference(serialNumber));
73 		}
74 
75 		streamHandler.endElement();
76 	}
77 
doPNEntry(int deviceNumberHigh, int deviceNumberLow)78 	public void doPNEntry(int deviceNumberHigh, int deviceNumberLow) throws HandlerException {
79 		streamHandler.startElement(new SystemUseEntryElement("PN", 1));
80 		streamHandler.data(new BothWordDataReference(deviceNumberHigh));
81 		streamHandler.data(new BothWordDataReference(deviceNumberLow));
82 		streamHandler.endElement();
83 	}
84 
startSLEntry(boolean continues)85 	public void startSLEntry(boolean continues) throws HandlerException {
86 		streamHandler.startElement(new SystemUseEntryElement("SL", 1));
87 		streamHandler.data(new ByteDataReference(continues ? 1 : 0));
88 	}
89 
doComponentRecord(int flags)90 	public void doComponentRecord(int flags) throws HandlerException {
91 		if (flags != CR_CONTINUES && flags != CR_CURRENT && flags != CR_PARENT && flags != CR_ROOT) {
92 			throw new HandlerException("Invalid Rock Ridge Component Record flags combination: " + flags);
93 		}
94 		streamHandler.data(new ByteDataReference(flags));
95 		streamHandler.data(new ByteDataReference(0));
96 	}
97 
doComponentRecord(DataReference name)98 	public void doComponentRecord(DataReference name) throws HandlerException {
99 		streamHandler.data(new ByteDataReference(0));
100 		streamHandler.data(new ByteDataReference(name.getLength()));
101 		streamHandler.data(name);
102 	}
103 
endSLEntry()104 	public void endSLEntry() throws HandlerException {
105 		streamHandler.endElement();
106 	}
107 
doNMEntry(int flags, DataReference name)108 	public void doNMEntry(int flags, DataReference name) throws HandlerException {
109 		streamHandler.startElement(new SystemUseEntryElement("NM", 1));
110 
111 		if (flags != 0 && flags != NM_CONTINUES && flags != NM_CURRENT && flags != NM_PARENT) {
112 			throw new HandlerException("Invalid Rock Ridge directory flags combination: " + flags);
113 		}
114 		streamHandler.data(new ByteDataReference(flags));
115 
116 		streamHandler.data(name);
117 		streamHandler.endElement();
118 	}
119 
doCLEntry()120 	public Fixup doCLEntry() throws HandlerException {
121 		streamHandler.startElement(new SystemUseEntryElement("CL", 1));
122 		Fixup childLocationFixup = streamHandler.fixup(new BothWordDataReference(0));
123 		streamHandler.endElement();
124 
125 		return childLocationFixup;
126 	}
127 
doPLEntry()128 	public Fixup doPLEntry() throws HandlerException {
129 		streamHandler.startElement(new SystemUseEntryElement("PL", 1));
130 		Fixup parentLocationFixup = streamHandler.fixup(new BothWordDataReference(0));
131 		streamHandler.endElement();
132 
133 		return parentLocationFixup;
134 	}
135 
doREEntry()136 	public void doREEntry() throws HandlerException {
137 		streamHandler.startElement(new SystemUseEntryElement("RE", 1));
138 		streamHandler.endElement();
139 	}
140 
doTFEntry(int type, ISO9660DateDataReference date)141 	public void doTFEntry(int type, ISO9660DateDataReference date) throws HandlerException {
142 		streamHandler.startElement(new SystemUseEntryElement("TF", 1));
143 
144 		checkTFType(type);
145 		streamHandler.data(new ByteDataReference(type | TF_LONG_FORM));
146 
147 		streamHandler.data(date);
148 		streamHandler.endElement();
149 	}
150 
doTFEntry(int type, ISO9660ShortDateDataReference date)151 	public void doTFEntry(int type, ISO9660ShortDateDataReference date) throws HandlerException {
152 		streamHandler.startElement(new SystemUseEntryElement("TF", 1));
153 
154 		checkTFType(type);
155 		streamHandler.data(new ByteDataReference(type));
156 
157 		streamHandler.data(date);
158 		streamHandler.endElement();
159 	}
160 
checkTFType(int type)161 	private void checkTFType(int type) throws HandlerException {
162 		if (type != TF_CREATION && type != TF_MODIFY && type !=	TF_ACCESS && type != TF_ATTRIBUTES
163 			&& type != TF_BACKUP && type != TF_EXPIRATION && type != TF_EFFECTIVE) {
164 			throw new HandlerException("Invalid Rock Ridge Timestamp type: " + type);
165 		}
166 	}
167 
doSFEntry(long virtualFileSizeHigh, long virtualFileSizeLow, int tableDepth)168 	public void doSFEntry(long virtualFileSizeHigh, long virtualFileSizeLow, int tableDepth) throws HandlerException {
169 		streamHandler.startElement(new SystemUseEntryElement("SF", 1));
170 		streamHandler.data(new BothWordDataReference(virtualFileSizeHigh));
171 		streamHandler.data(new BothWordDataReference(virtualFileSizeLow));
172 		streamHandler.data(new ByteDataReference(tableDepth));
173 		streamHandler.endElement();
174 	}
175 
doEREntry()176 	public void doEREntry() throws HandlerException {
177 		String id, descriptor, source;
178 		if (RRIPFactory.MKISOFS_COMPATIBILITY) {
179 			id = "RRIP_1991A";
180 			descriptor = "THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS";
181 			source = "PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE.  SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR CONTACT INFORMATION";
182 		} else {
183 			id = "IEEE 1282";
184 			descriptor = "THE IEEE 1282 PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS.";
185 			source = "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, PISCATAWAY, NJ, USA FOR THE 1282 SPECIFICATION.";
186 		}
187 
188 		// TODO Handle character sets
189 		ByteArrayDataReference idRef = new ByteArrayDataReference(id.getBytes());
190 		ByteArrayDataReference descriptorRef = new ByteArrayDataReference(descriptor.getBytes());
191 		ByteArrayDataReference sourceRef = new ByteArrayDataReference(source.getBytes());
192 
193 		doEREntry(idRef, descriptorRef, sourceRef, 1);
194 	}
195 
doRREntry(int flags)196 	public void doRREntry(int flags) throws HandlerException {
197 		if (MKISOFS_COMPATIBILITY) {
198 			if (flags<0 || flags>255) {
199 				throw new HandlerException("Invalid RR flags: " + flags);
200 			}
201 
202 			streamHandler.startElement(new SystemUseEntryElement("RR", 1));
203 			streamHandler.data(new ByteDataReference(flags));
204 			streamHandler.endElement();
205 		}
206 		// Else: Do nothing (RRIP 1.12 does not include the RR Entry type)
207 	}
208 }
209