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