1 // Key.h 2 // 3 // Copyright (c) 2003, Ingo Weinhold (bonefish@cs.tu-berlin.de) 4 // 5 // This program is free software; you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation; either version 2 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with this program; if not, write to the Free Software 17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 // 19 // You can alternatively use *this file* under the terms of the the MIT 20 // license included in this package. 21 22 #ifndef KEY_H 23 #define KEY_H 24 25 #include <new> 26 27 #include <stdio.h> 28 29 #include <SupportDefs.h> 30 31 #include "Debug.h" 32 #include "endianess.h" 33 34 using std::nothrow; 35 36 // Key 37 /*! 38 \class Key 39 \brief Represents the on-disk structure for a key. 40 41 Unfortunately there exist two different key formats and one can not 42 always guess the right format from the data. That makes the implementation 43 of the class a bit messy. This and the endianess awareness code, that is 44 particularly ugly for the bitfields (hopefully at least correct). 45 */ 46 class Key : private key { 47 public: 48 Key() {} 49 Key(const Key &k) : key(k) {} 50 ~Key() {} 51 52 static Key* CastFrom(key* k) 53 { return static_cast<Key*>(k); } 54 static const Key* CastFrom(const key* k) 55 { return static_cast<const Key*>(k); } 56 57 void SetTo(uint32 dirID, uint32 objectID, uint64 offset, uint32 type, 58 uint16 version) 59 { 60 k_dir_id = h2le(dirID); 61 k_objectid = h2le(objectID); 62 if (version == KEY_FORMAT_3_5) { 63 u.k_offset_v1.k_offset = h2le((uint32)offset); 64 u.k_offset_v1.k_uniqueness = h2le(type); 65 } else 66 _SetOffsetAndType(offset, type); 67 } 68 69 uint16 GuessVersion() const 70 { 71 // assume old format, unless detected otherwise 72 switch (_GetType()) { 73 case TYPE_DIRECT: 74 case TYPE_INDIRECT: 75 case TYPE_DIRENTRY: 76 return KEY_FORMAT_3_6; 77 default: 78 return KEY_FORMAT_3_5; 79 } 80 } 81 uint32 GetDirID() const { return le2h(k_dir_id); } 82 uint32 GetObjectID() const { return le2h(k_objectid); } 83 uint64 GetOffset(uint16 version) const 84 { 85 return (version == KEY_FORMAT_3_6 ? _GetOffset() 86 : le2h(u.k_offset_v1.k_offset)); 87 } 88 // uint64 GetOffset() const { return GetOffset(GuessVersion()); } 89 void SetOffset(uint64 offset, uint16 version) 90 { 91 if (version == KEY_FORMAT_3_6) 92 _SetOffsetAndType(offset, _GetType()); 93 else 94 u.k_offset_v1.k_offset = h2le(offset); 95 } 96 uint16 GetType(uint16 version) const 97 { 98 // current version 99 if (version == KEY_FORMAT_3_6) 100 return _GetType(); 101 // old version 102 switch (le2h(u.k_offset_v1.k_uniqueness)) { 103 case V1_SD_UNIQUENESS: 104 return TYPE_STAT_DATA; 105 case V1_INDIRECT_UNIQUENESS: 106 return TYPE_INDIRECT; 107 case V1_DIRECT_UNIQUENESS: 108 return TYPE_DIRECT; 109 case V1_DIRENTRY_UNIQUENESS: 110 return TYPE_DIRENTRY; 111 case V1_ANY_UNIQUENESS: 112 default: 113 return TYPE_ANY; 114 } 115 } 116 // uint16 GetType() const { return GetType(GuessVersion()); } 117 118 Key &operator=(const Key &k) 119 { 120 *static_cast<key*>(this) = k; 121 return *this; 122 } 123 124 private: 125 // helpers for accessing k_offset_v2 126 uint64 _GetOffset() const 127 { 128 #if LITTLE_ENDIAN 129 return u.k_offset_v2.k_type; 130 #else 131 offset_v2 temp; 132 *(uint64*)&temp = h2le(*(uint64*)&u.k_offset_v2); 133 return temp.k_offset; 134 #endif 135 } 136 uint32 _GetType() const 137 { 138 #if LITTLE_ENDIAN 139 return u.k_offset_v2.k_type; 140 #else 141 offset_v2 temp; 142 *(uint64*)&temp = h2le(*(uint64*)&u.k_offset_v2); 143 return temp.k_type; 144 #endif 145 } 146 void _SetOffsetAndType(uint64 offset, uint32 type) 147 { 148 u.k_offset_v2.k_offset = offset; 149 u.k_offset_v2.k_type = type; 150 #if !LITTLE_ENDIAN 151 *(uint64*)&u.k_offset_v2 = h2le(*(uint64*)&u.k_offset_v2); 152 #endif 153 } 154 }; 155 156 157 // VKey -- a versioned key 158 /*! 159 \class VKey 160 \brief Wraps a Key and adds format version information. 161 162 This class is much more useful than Key. It knows its format version and 163 adds comparison operators. Note, that the operators do NOT compare the 164 type fields of the key. If that is needed, the Compare() method has 165 a flag for it. 166 */ 167 class VKey { 168 private: 169 void _Unset() { if (fVersion & ALLOCATED) delete fKey; fKey = NULL; } 170 171 public: 172 VKey() : fKey(NULL), fVersion(KEY_FORMAT_3_5) {} 173 VKey(const Key *k, uint32 version) 174 : fKey(const_cast<Key*>(k)), fVersion(version) {} 175 VKey(const Key *k) : fKey(NULL), fVersion(KEY_FORMAT_3_5) { SetTo(k); } 176 VKey(uint32 dirID, uint32 objectID, uint64 offset, uint32 type, 177 uint16 version) 178 : fKey(NULL), fVersion(KEY_FORMAT_3_5) 179 { 180 SetTo(dirID, objectID, offset, type, version); 181 } 182 VKey(const VKey &k) 183 : fKey(new(nothrow) Key(*k.fKey)), fVersion(k.fVersion | ALLOCATED) {} 184 ~VKey() { _Unset(); } 185 186 void SetTo(const Key *k, uint32 version) 187 { 188 _Unset(); 189 fKey = const_cast<Key*>(k); 190 fVersion = version; 191 } 192 void SetTo(const Key *k) 193 { 194 _Unset(); 195 fKey = const_cast<Key*>(k); 196 fVersion = fKey->GuessVersion(); 197 } 198 void SetTo(uint32 dirID, uint32 objectID, uint64 offset, uint32 type, 199 uint16 version) 200 { 201 _Unset(); 202 fKey = new(nothrow) Key; 203 if (version == KEY_FORMAT_3_5) 204 fVersion = KEY_FORMAT_3_5 | ALLOCATED; 205 else 206 fVersion = KEY_FORMAT_3_6 | ALLOCATED; 207 fKey->SetTo(dirID, objectID, offset, type, fVersion); 208 } 209 210 uint16 GetVersion() const { return fVersion & VERSION_MASK; } 211 uint32 GetDirID() const { return fKey->GetDirID(); } 212 uint32 GetObjectID() const { return fKey->GetObjectID(); } 213 uint64 GetOffset() const { return fKey->GetOffset(GetVersion()); } 214 uint16 GetType() const { return fKey->GetType(GetVersion()); } 215 216 void SetOffset(uint64 offset) 217 { return fKey->SetOffset(offset, GetVersion()); } 218 219 int Compare(const VKey &k, bool compareTypes = false) const 220 { 221 if (GetDirID() < k.GetDirID()) 222 return -1; 223 if (GetDirID() > k.GetDirID()) 224 return 1; 225 if (GetObjectID() < k.GetObjectID()) 226 return -1; 227 if (GetObjectID() > k.GetObjectID()) 228 return 1; 229 int64 dOffset = (int64)GetOffset() - (int64)k.GetOffset(); 230 if (dOffset < 0) 231 return -1; 232 if (dOffset > 0) 233 return 1; 234 if (compareTypes) { 235 int32 dType = (int32)GetType() - (int32)k.GetType(); 236 if (dType < 0) 237 return -1; 238 if (dType > 0) 239 return 1; 240 } 241 return 0; 242 } 243 // Note: The operators don't compare the types! Use Compare(, true), if 244 // you want to do that. 245 bool operator==(const VKey &k) const { return (Compare(k) == 0); } 246 bool operator!=(const VKey &k) const { return (Compare(k) != 0); } 247 bool operator<(const VKey &k) const { return (Compare(k) < 0); } 248 bool operator>(const VKey &k) const { return (Compare(k) > 0); } 249 bool operator<=(const VKey &k) const { return (Compare(k) <= 0); } 250 bool operator>=(const VKey &k) const { return (Compare(k) >= 0); } 251 252 VKey &operator=(const VKey &k) 253 { 254 if (!(fVersion & ALLOCATED)) 255 fKey = new(nothrow) Key; 256 *fKey = *k.fKey; 257 fVersion |= ALLOCATED; 258 return *this; 259 } 260 261 void Dump() const 262 { 263 TPRINT(("key: {%" B_PRIu32 ", %" B_PRIu32 ", %" B_PRIu64 ", %hu}\n", 264 GetDirID(), GetObjectID(), GetOffset(), GetType())); 265 } 266 267 private: 268 enum { 269 VERSION_MASK = KEY_FORMAT_3_5 | KEY_FORMAT_3_6, 270 ALLOCATED = 0x8000 271 }; 272 273 private: 274 Key *fKey; 275 uint16 fVersion; 276 }; 277 278 #endif // KEY_H 279