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