1 /*	$NetBSD: cd9660_conversion.c,v 1.4 2007/03/14 14:11:17 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
5  * Perez-Rathke and Ram Vedam.  All rights reserved.
6  *
7  * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
8  * Alan Perez-Rathke and Ram Vedam.
9  *
10  * Redistribution and use in source and binary forms, with or
11  * without modification, are permitted provided that the following
12  * conditions are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above
16  *    copyright notice, this list of conditions and the following
17  *    disclaimer in the documentation and/or other materials provided
18  *    with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
21  * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24  * DISCLAIMED.  IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
25  * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28  * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
32  * OF SUCH DAMAGE.
33  */
34 
35 #define CD9660_CONVERSION_IMPL
36 #include "cd9660.h"
37 
38 #include <sys/cdefs.h>
39 #if defined(__RCSID) && !defined(__lint)
40 __RCSID("$NetBSD: cd9660_conversion.c,v 1.4 2007/03/14 14:11:17 christos Exp $");
41 __IDSTRING(mbsdid, "$MirOS: src/usr.sbin/makefs/cd9660/cd9660_conversion.c,v 1.8 2010/03/06 22:38:48 tg Exp $");
42 #endif  /* !__lint */
43 
44 
45 static char cd9660_compute_gm_offset(time_t);
46 
47 #if 0
48 static inline int
49 cd9660_pad_even(length)
50 int length;
51 {
52 	return length + (length & 0x01);
53 }
54 #endif
55 
56 /*
57 * These can probably be implemented using a macro
58 */
59 
60 /* Little endian */
61 void
cd9660_721(uint16_t w,unsigned char * twochar)62 cd9660_721(uint16_t w, unsigned char *twochar)
63 {
64 #if BYTE_ORDER == BIG_ENDIAN
65 	w = bswap16(w);
66 #endif
67 	memcpy(twochar,&w,2);
68 }
69 
70 void
cd9660_731(uint32_t w,unsigned char * fourchar)71 cd9660_731(uint32_t w, unsigned char *fourchar)
72 {
73 #if BYTE_ORDER == BIG_ENDIAN
74 	w = bswap32(w);
75 #endif
76 	memcpy(fourchar,&w,4);
77 }
78 
79 /* Big endian */
80 void
cd9660_722(uint16_t w,unsigned char * twochar)81 cd9660_722(uint16_t w, unsigned char *twochar)
82 {
83 #if BYTE_ORDER == LITTLE_ENDIAN
84 	w = bswap16(w);
85 #endif
86 	memcpy(twochar,&w,2);
87 }
88 
89 void
cd9660_732(uint32_t w,unsigned char * fourchar)90 cd9660_732(uint32_t w, unsigned char *fourchar)
91 {
92 #if BYTE_ORDER == LITTLE_ENDIAN
93 	w = bswap32(w);
94 #endif
95 	memcpy(fourchar,&w,4);
96 }
97 
98 /**
99 * Convert a dword into a double endian string of eight characters
100 * @param int The double word to convert
101 * @param char* The string to write the both endian double word to - It is assumed this is allocated and at least
102 *		eight characters long
103 */
104 void
cd9660_bothendian_dword(uint32_t dw,unsigned char * eightchar)105 cd9660_bothendian_dword(uint32_t dw, unsigned char *eightchar)
106 {
107 	uint32_t le, be;
108 #if BYTE_ORDER == LITTLE_ENDIAN
109 	le = dw;
110 	be = bswap32(dw);
111 #endif
112 #if BYTE_ORDER == BIG_ENDIAN
113 	be = dw;
114 	le = bswap32(dw);
115 #endif
116 	memcpy(eightchar, &le, 4);
117 	memcpy((eightchar+4), &be, 4);
118 }
119 
120 /**
121 * Convert a word into a double endian string of four characters
122 * @param int The word to convert
123 * @param char* The string to write the both endian word to - It is assumed this is allocated and at least
124 *		four characters long
125 */
126 void
cd9660_bothendian_word(uint16_t dw,unsigned char * fourchar)127 cd9660_bothendian_word(uint16_t dw, unsigned char *fourchar)
128 {
129 	uint16_t le, be;
130 #if BYTE_ORDER == LITTLE_ENDIAN
131 	le = dw;
132 	be = bswap16(dw);
133 #endif
134 #if BYTE_ORDER == BIG_ENDIAN
135 	be = dw;
136 	le = bswap16(dw);
137 #endif
138 	memcpy(fourchar, &le, 2);
139 	memcpy((fourchar+2), &be, 2);
140 }
141 
142 void
cd9660_pad_string_spaces_(char * str,size_t len)143 cd9660_pad_string_spaces_(char *str, size_t len)
144 {
145 	size_t i;
146 
147 	for (i = 0; i < len; i ++) {
148 		if (str[i] == '\0')
149 			str[i] = 0x20;
150 	}
151 }
152 
153 static char
cd9660_compute_gm_offset(time_t tim)154 cd9660_compute_gm_offset(time_t tim)
155 {
156 	struct tm t, gm;
157 
158 	(void)localtime_r(&tim, &t);
159 	(void)gmtime_r(&tim, &gm);
160 	gm.tm_year -= t.tm_year;
161 	gm.tm_yday -= t.tm_yday;
162 	gm.tm_hour -= t.tm_hour;
163 	gm.tm_min  -= t.tm_min;
164 	if (gm.tm_year < 0)
165 		gm.tm_yday = -1;
166 	else if (gm.tm_year > 0)
167 		gm.tm_yday = 1;
168 
169 	return (char)(-(gm.tm_min + 60* (24 * gm.tm_yday + gm.tm_hour)) / 15);
170 }
171 
172 /* Long dates: 17 characters */
173 void
cd9660_time_8426(time_t tim,unsigned char * buf)174 cd9660_time_8426(time_t tim, unsigned char *buf)
175 {
176 	struct tm t;
177 	char temp[18];
178 
179 	(void)localtime_r(&tim, &t);
180 	(void)snprintf(temp, sizeof(temp), "%04i%02i%02i%02i%02i%02i%02i",
181 		1900+(int)t.tm_year,
182 		(int)t.tm_mon+1,
183 		(int)t.tm_mday,
184 		(int)t.tm_hour,
185 		(int)t.tm_min,
186 		(int)t.tm_sec,
187 		0);
188 	(void)memcpy(buf, temp, 16);
189 	buf[16] = cd9660_compute_gm_offset(tim);
190 }
191 
192 /* Short dates: 7 characters */
193 void
cd9660_time_915(time_t tim,unsigned char * buf)194 cd9660_time_915(time_t tim, unsigned char *buf)
195 {
196 	struct tm t;
197 
198 	(void)localtime_r(&tim, &t);
199 	buf[0] = t.tm_year;
200 	buf[1] = t.tm_mon+1;
201 	buf[2] = t.tm_mday;
202 	buf[3] = t.tm_hour;
203 	buf[4] = t.tm_min;
204 	buf[5] = t.tm_sec;
205 	buf[6] = cd9660_compute_gm_offset(tim);
206 }
207 
208 int
cd9660_isthisa_time_8426_utc(const char * val,const char * fieldtitle)209 cd9660_isthisa_time_8426_utc(const char *val, const char *fieldtitle)
210 {
211 	int i, j;
212 
213 	if (val == NULL || strlen(val) != 16) {
214 		warnx("error: The %s requires a 16 bytes 8.4.26 time argument",
215 		     fieldtitle);
216 		return (0);
217 	}
218 
219 	j = 0;
220 	for (i = 0; i < 16; ++i)
221 		if (val[i] < '0' || val[i] > '9') {
222 			warnx("error: The %s must be composed of digits",
223 			    fieldtitle);
224 			return (0);
225 		} else if (val[i] != '0')
226 			j = 1;
227 
228 	if (j == 0)
229 		/* 16 times '0' */
230 		return (1);
231 
232 #define otoa(x) (val[x] - '0')
233 
234 	if (val[0] == '0' && val[1] == '0' && val[2] == '0' && val[3] == '0') {
235 		warnx("error: The %s %s is invalid (%s)", fieldtitle,
236 		    "year", "too small");
237 		return (0);
238 	}
239 
240 	i = otoa(4) * 10 + otoa(5);
241 	if (i < 1 || i > 12) {
242 		warnx("error: The %s %s is invalid (%s)", fieldtitle,
243 		    "month", "not 1..12");
244 		return (0);
245 	}
246 
247 	i = otoa(6) * 10 + otoa(7);
248 	if (i < 1 || i > 31) {
249 		warnx("error: The %s %s is invalid (%s)", fieldtitle,
250 		    "day", "not 1..31");
251 		return (0);
252 	}
253 
254 	i = otoa(8) * 10 + otoa(9);
255 	if (i > 23) {
256 		warnx("error: The %s %s is invalid (%s)", fieldtitle,
257 		    "hour", "not 0..23");
258 		return (0);
259 	}
260 
261 	i = otoa(10) * 10 + otoa(11);
262 	if (i > 59) {
263 		warnx("error: The %s %s is invalid (%s)", fieldtitle,
264 		    "minute", "not 0..59");
265 		return (0);
266 	}
267 
268 	i = otoa(12) * 10 + otoa(13);
269 	if (i > 59) {
270 		/* but in ECMA 119: should be 0..60 */
271 		warnx("error: The %s %s is invalid (%s)", fieldtitle,
272 		    "second", "not 0..59");
273 		return (0);
274 	}
275 
276 #undef otoa
277 
278 	/* hundredths are 00..99 alright */
279 	/* offset is NUL (UTC) alright */
280 	return (1);
281 }
282