1 //---------------------------------------------------------------------- 2 // This software is part of the Haiku distribution and is covered 3 // by the MIT 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 15 extern "C" { 16 #ifndef _IMPEXP_KERNEL 17 # define _IMPEXP_KERNEL 18 #endif 19 20 extern int32 timezone_offset; 21 } 22 23 24 namespace Udf { 25 26 long_address 27 to_long_address(ino_t id, uint32 length) 28 { 29 DEBUG_INIT_ETC(NULL, ("ino_t: %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 38 ino_t 39 to_vnode_id(long_address address) 40 { 41 DEBUG_INIT(NULL); 42 ino_t 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(("ino_t: %Ld, 0x%Lx\n", result, result)); 49 return result; 50 } 51 52 time_t 53 make_time(timestamp ×tamp) 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 */ 109 status_t 110 Udf::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 */ 133 const char* 134 Udf::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 */ 144 status_t 145 Udf::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 */ 161 uint16 162 Udf::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