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 ×tamp) 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