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