Menu

Attribute_RT.h

Go to the documentation of this file.
00001 /*******************************************************************************
00002  *
00003  * Copyright (c) 2008-2010 Michael Schulze <mschulze@ivs.cs.uni-magdeburg.de>
00004  *                    2010 Marcus Foerster <MarcusFoerster1@gmx.de>
00005  * All rights reserved.
00006  *
00007  *    Redistribution and use in source and binary forms, with or without
00008  *    modification, are permitted provided that the following conditions
00009  *    are met:
00010  *
00011  *    * Redistributions of source code must retain the above copyright
00012  *      notice, this list of conditions and the following disclaimer.
00013  *
00014  *    * Redistributions in binary form must reproduce the above copyright
00015  *      notice, this list of conditions and the following disclaimer in
00016  *      the documentation and/or other materials provided with the
00017  *      distribution.
00018  *
00019  *    * Neither the name of the copyright holders nor the names of
00020  *      contributors may be used to endorse or promote products derived
00021  *      from this software without specific prior written permission.
00022  *
00023  *
00024  *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
00025  *    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00026  *    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00027  *    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00028  *    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00029  *    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00030  *    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00031  *    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00032  *    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00033  *    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00034  *    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00035  *
00036  *
00037  * $Id$
00038  *
00039  ******************************************************************************/
00040 
00041 #ifndef _Attribute_RT_h_
00042 #define _Attribute_RT_h_
00043 
00044 #include <stdint.h>
00045 
00046 #include "util/generic_endianess.h"
00047 
00048 #include "mw/attributes/detail/AttributeElementHeader.h"
00049 #include "mw/attributes/access/AttributeHeader_RT.h"
00050 
00051 namespace famouso {
00052     namespace mw {
00053         namespace attributes {
00054             namespace access {
00055 
00072                 class Attribute_RT : public AttributeHeader_RT {
00073                     protected:
00074                         Attribute_RT() {
00075                             // Visibility
00076                         }
00077 
00078                         // TODO: Think about the usage of CaseSelector<>::select_rt() for
00079                         //  getting and setting the attribute's value or even for all
00080                         //  case specific implementations of attribute runtime access
00081 
00082                     public:
00094                         template <typename ValueType>
00095                         const ValueType getValue() const {
00096                             // The result (in big endian order first, it will be converted when
00097                             //  it is returned)
00098                             ValueType res;
00099 
00100                             const uint8_t* const data = reinterpret_cast<const uint8_t* const>(this);
00101 
00102                             const elemHeader_t* const header = asElementHeader();
00103 
00104                             if ((header->isHighDensity()) && (!header->lengthValueSwitch)) {
00105                                 // We have a HD-attribute with its value encoded as a part of the header
00106 
00107                                 if (header->extension) {
00108                                     if (sizeof(ValueType) == 1) {
00109                                         // If the value type has only one byte, the two remaining bits
00110                                         //  of the header byte are zero, since all 8 bits of the value
00111                                         //  fit the extended byte
00112                                         // (Implicit conversion: data[1] -> uint8_t -> static_cast -> ValueType)
00113                                         res = static_cast<ValueType>(data[1]);
00114                                     } else {
00115                                         // In all other cases the 10 bits of the 2-byte-header must be used
00116                                         const uint16_t tmp = *(reinterpret_cast<const uint16_t* const>(data));
00117 
00118                                         // Adjust endianess and mask out the upper 6 header meta-bits
00119                                         res = (famouso::util::ntoh(tmp) & 0x3FF);
00120                                     }
00121                                 } else {
00122                                     res = static_cast<ValueType> (data[0] & 0x3);
00123                                 }
00124                             } else {
00125                                 // Initialize the result to zeros
00126                                 res = ValueType();
00127 
00128                                 // Pointer to the attribute value
00129                                 const uint8_t* valPtr;
00130 
00131                                 // Number of bytes to copy from the val-array
00132                                 uint16_t length;
00133 
00134                                 const uint16_t lengthMask  = ((header->isHighDensity()) ? 0x3FF : 0x7FF);
00135                                 const uint8_t  valueOffset = ((header->isHighDensity()) ? 1 : 2);
00136 
00137                                 // Read the length in big-endian order
00138                                 if (header->extension) {
00139                                     length = *(reinterpret_cast<const uint16_t*>(data));
00140                                     length = (ntohs(length) & lengthMask);
00141                                     valPtr = &data[valueOffset + 1];
00142                                 } else {
00143                                     // Expand the single byte to a 16 bit value and only apply the
00144                                     //  high byte of the mask (0x3)
00145                                     length = static_cast<uint16_t>(data[0] & 0x3);
00146                                     valPtr = &data[valueOffset];
00147                                 }
00148 
00149                                 // Interpret the result as a byte array to copy every single byte
00150                                 uint8_t* resPtr = reinterpret_cast<uint8_t* const>(&res) +
00151                                                   sizeof(ValueType) - 1;
00152                                 // Set the value pointer to the last byte of the value
00153                                 valPtr += (length - 1);
00154 
00155                                 while (length-- > 0) {
00156                                     *resPtr-- = *valPtr--;
00157                                 }
00158 
00159                                 res = famouso::util::ntoh(res);
00160                             }
00161 
00162                             return (res);
00163                         }
00164 
00184                         template <typename ValueType>
00185                         const bool setValue(const ValueType newValue) {
00186                             uint8_t* const data = reinterpret_cast<uint8_t* const>(this);
00187 
00188                             // Determine the bit count of the value to set
00189                             const uint16_t newBitCount = getBitCount(newValue);
00190 
00191                             elemHeader_t* const header = asElementHeader();
00192 
00193                             if ((header->isHighDensity()) && (!header->lengthValueSwitch)) {
00194                                 if (header->extension) {
00195                                     // 10 bits at max are allowed in this case
00196                                     if (newBitCount > 10)
00197                                         return (false);
00198 
00199                                     if (sizeof(ValueType) == 1) {
00200                                         // If the given value has only one byte, the 2 bits of the header
00201                                         //  must be cleared and the extended byte is set to the given value
00202 
00203                                         header->valueOrLength = 0x0;
00204 
00205                                         data[1] = static_cast<uint8_t>(newValue);
00206                                     } else {
00207                                         // This case can never be reached by a negative value (it would have
00208                                         //  taken 16 bits, which is not allowed here)
00209 
00210                                         // Convert the given value to big endian order
00211                                         const ValueType bigEndian = famouso::util::hton(newValue);
00212 
00213                                         // In all other cases the lower 10 bits of the given value must be
00214                                         //  copied into the binary representation
00215                                         // Retrieve a pointer and move it to the last byte of the value
00216                                         const uint8_t* const tmp = reinterpret_cast<const uint8_t* const>(&bigEndian) +
00217                                                                    sizeof(ValueType) - 1;
00218 
00219                                         // Copy the lowest 2 bits of the header
00220                                         header->valueOrLength = (*(tmp - 1) & 0x3);
00221                                         // Copy into the extended byte
00222                                         data[1] = *tmp;
00223                                     }
00224                                 } else {
00225                                     // Only 2 bits at max are allowed here
00226                                     if (newBitCount > 2)
00227                                         return (false);
00228 
00229                                     // This case can never be reached by a negative value (it takes 8 bits at least)
00230                                     //  so it is legal to simply mask the lowest 2 bits
00231 
00232                                     // Simply write the lowest 3 bits to the header
00233                                     header->valueOrLength = (newValue & 0x3);
00234                                 }
00235                             } else {
00236                                 // Determine the byte count needed by the new value (this is necessary since
00237                                 //  we only write whole bytes if the VOL flag isn't set)
00238                                 const uint16_t newByteCount = bitCountToByteCount(newBitCount);
00239 
00240                                 // The pointer where to start copying the bytes of the new value
00241                                 //  (depends on the extension flag)
00242                                 uint8_t* targetPtr;
00243                                 // The length read
00244                                 // TODO: Use AttributeHeader_RT.getLength() here
00245                                 uint16_t length;
00246 
00247                                 const uint8_t valueOffset = ((header->isHighDensity()) ? 1 : 2);
00248 
00249                                 // Read the length in big-endian order
00250                                 if (header->extension) {
00251                                     length    = *(reinterpret_cast<const uint16_t*>(data));
00252                                     length    = (ntohs(length) & ((header->isHighDensity()) ? 0x3FF : 0x7FF));
00253                                     targetPtr = &data[valueOffset + 1];
00254                                 } else {
00255                                     // Expand the single byte to a 16 bit value and only apply the
00256                                     //  high byte of the mask (0x3)
00257                                     length    = static_cast<uint16_t>(data[0] & 0x3);
00258                                     targetPtr = &data[valueOffset];
00259                                 }
00260 
00261                                 // Check if the new byte count does not violate the old one
00262                                 if (newByteCount > length) return (false);
00263 
00264                                 // Convert the given value to big endian order
00265                                 const ValueType bigEndian = famouso::util::hton(newValue);
00266                                 // Get a pointer to the big endian representation
00267                                 const uint8_t* const newValPtr =
00268                                         reinterpret_cast<const uint8_t*>(&bigEndian) + (sizeof(ValueType) - length);
00269 
00270                                 // Copy the value (we even copy the possible zero bytes of the new value to
00271                                 //  zero out the bytes not needed, the length must not be decreased since
00272                                 //  it would make iterating over the byte sequence impossible)
00273                                 for (uint16_t i = 0; i < length; ++i) {
00274                                     targetPtr[i] = newValPtr[i];
00275                                 }
00276                             }
00277 
00278                             return (true);
00279                         }
00280 
00287                         uint16_t length() const {
00288                             // The sum of the header size (which eventually includes an encoded
00289                             //  attribute value) and the encoded length is the overall size of
00290                             //  the attribute
00291                             return (headerLength() + valueLength());
00292                         }
00293 
00294                 };
00295 
00296             } // end namespace access
00297         } // end namespace attributes
00298     } // end namespace mw
00299 } // end namespace famouso
00300 
00301 #endif // _Attribute_h_