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