xref: /haiku/src/add-ons/kernel/file_systems/udf/Utils.cpp (revision 16d5c24e533eb14b7b8a99ee9f3ec9ba66335b1e)
1 /*
2  * Copyright 2003, Tyler Dauwalder, tyler@dauwalder.net.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 /*! \file Utils.cpp - Miscellaneous Udf utility functions. */
7 
8 #include "Utils.h"
9 
10 extern "C" {
11 	extern int32 timezone_offset;
12 }
13 
14 /*! \brief Returns "true" if \a value is true, "false" otherwise. */
15 const char*
16 bool_to_string(bool value)
17 {
18 	return value ? "true" : "false";
19 }
20 
21 
22 /*! \brief Calculates the UDF crc checksum for the given byte stream.
23 
24 	Based on crc code from UDF-2.50 6.5, as permitted.
25 
26 	\param data Pointer to the byte stream.
27 	\param length Length of the byte stream in bytes.
28 
29 	\return The crc checksum, or 0 if an error occurred.
30 */
31 uint16
32 calculate_crc(uint8 *data, uint16 length)
33 {
34 	uint16 crc = 0;
35 	if (data) {
36 		for ( ; length > 0; length--, data++)
37 			crc = kCrcTable[(crc >> 8 ^ *data) & 0xff] ^ (crc << 8);
38 	}
39 	return crc;
40 }
41 
42 
43 /*! \brief Takes an overloaded ssize_t return value like those returned
44 	by BFile::Read() and friends, as well as an expected number of bytes,
45 	and returns B_OK if the byte counts match, or the appropriate error
46 	code otherwise.
47 */
48 status_t
49 check_size_error(ssize_t bytesReturned, ssize_t bytesExpected)
50 {
51 	return bytesReturned == bytesExpected
52 		? B_OK : (bytesReturned >= 0 ? B_IO_ERROR : status_t(bytesReturned));
53 }
54 
55 
56 /*! \brief Calculates the block shift amount for the given
57  	block size, which must be a positive power of 2.
58 */
59 status_t
60 get_block_shift(uint32 blockSize, uint32 &blockShift)
61 {
62 	if (blockSize == 0)
63 		return B_BAD_VALUE;
64 	uint32 bitCount = 0;
65 	uint32 result = 0;
66 	for (int i = 0; i < 32; i++) {
67 		// Zero out all bits except bit i
68 		uint32 block = blockSize & (uint32(1) << i);
69 		if (block) {
70 			if (++bitCount > 1)
71 				return B_BAD_VALUE;
72 			else
73 				result = i;
74 		}
75 	}
76 	blockShift = result;
77 	return B_OK;
78 }
79 
80 
81 time_t
82 make_time(timestamp &timestamp)
83 {
84 	DEBUG_INIT_ETC(NULL, ("timestamp: (tnt: 0x%x, type: %d, timezone: %d = 0x%x, year: %d, "
85 	           "month: %d, day: %d, hour: %d, minute: %d, second: %d)", timestamp.type_and_timezone(),
86 	           timestamp.type(), timestamp.timezone(),
87 	            timestamp.timezone(),timestamp.year(),
88 	           timestamp.month(), timestamp.day(), timestamp.hour(), timestamp.minute(), timestamp.second()));
89 
90 	time_t result = 0;
91 
92 	if (timestamp.year() >= 1970) {
93 		const int monthLengths[12]
94 			= { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
95 
96 		int year = timestamp.year();
97 		int month = timestamp.month();
98 		int day = timestamp.day();
99 		int hour = timestamp.hour();
100 		int minute = timestamp.minute();
101 		int second = timestamp.second();
102 
103 		// Range check the timezone offset, then round it down
104 		// to the nearest hour, since no one I know treats timezones
105 		// with a per-minute granularity, and none of the other OSes
106 		// I've looked at appear to either.
107 		int timezone_offset = timestamp.timezone();
108 		if (-1440 > timezone_offset || timezone_offset > 1440)
109 			timezone_offset = 0;
110 		timezone_offset -= timezone_offset % 60;
111 
112 		int previousLeapYears = (year - 1968) / 4;
113 		bool isLeapYear = (year - 1968) % 4 == 0;
114 		if (isLeapYear)
115 			--previousLeapYears;
116 
117 		// Years to days
118 		result = (year - 1970) * 365 + previousLeapYears;
119 		// Months to days
120 		for (int i = 0; i < month-1; i++) {
121 			result += monthLengths[i];
122 		}
123 		if (month > 2 && isLeapYear)
124 			++result;
125 		// Days to hours
126 		result = (result + day - 1) * 24;
127 		// Hours to minutes
128 		result = (result + hour) * 60 + timezone_offset;
129 		// Minutes to seconds
130 		result = (result + minute) * 60 + second;
131 	}
132 
133 	return result;
134 }
135 
136 
137 long_address
138 to_long_address(ino_t id, uint32 length)
139 {
140 	TRACE(("udf_to_long_address: ino_t = %Ld (0x%Lx), length = %ld",
141 		id, id, length));
142 	long_address result;
143 	result.set_block((id >> 16) & 0xffffffff);
144 	result.set_partition(id & 0xffff);
145 	result.set_length(length);
146 	DUMP(result);
147 	return result;
148 }
149 
150 
151 ino_t
152 to_vnode_id(long_address address)
153 {
154 	DEBUG_INIT(NULL);
155 	ino_t result = address.block();
156 	result <<= 16;
157 	result |= address.partition();
158 	TRACE(("block:     %ld, 0x%lx\n", address.block(), address.block()));
159 	TRACE(("partition: %d, 0x%x\n", address.partition(), address.partition()));
160 	TRACE(("length:    %ld, 0x%lx\n", address.length(), address.length()));
161 	TRACE(("ino_t:     %Ld, 0x%Lx\n", result, result));
162 	return result;
163 }
164