Ejemplo n.º 1
0
NTSTATUS
LZOPTDecompressBuffer (
    OUT PUCHAR UncompressedBuffer,
    IN ULONG UncompressedBufferSize,
    IN PUCHAR CompressedBuffer,
    IN ULONG CompressedBufferSize,
    OUT PULONG FinalUncompressedSize
    )

/*++

Routine Description:

    This routine takes as input a compressed buffer and produces
    its uncompressed equivalent provided the uncompressed data fits
    within the specified destination buffer.

    An output variable indicates the number of bytes used to store the
    uncompressed data.

Arguments:

    UncompressedBuffer - Supplies a pointer to where the uncompressed
        data is to be stored.

    UncompressedBufferSize - Supplies the size, in bytes, of the
        uncompressed buffer.

    CompressedBuffer - Supplies a pointer to the compressed data.

    CompressedBufferSize - Supplies the size, in bytes, of the
        compressed buffer.

    FinalUncompressedSize - Receives the number of bytes needed in
        the uncompressed buffer to store the uncompressed data.

    WorkSpace - Don't be nosy.

Return Value:

    STATUS_SUCCESS - the decompression worked without a hitch.

    STATUS_BAD_COMPRESSION_BUFFER - the input compressed buffer is
        ill-formed.

--*/

{
    NTSTATUS Status;

    PUCHAR CompressedChunk = CompressedBuffer;
    PUCHAR UncompressedChunk = UncompressedBuffer;

    COMPRESSED_CHUNK_HEADER ChunkHeader;
    LONG SavedChunkSize;

    LONG UncompressedChunkSize;
    LONG CompressedChunkSize;

    //
    //  The following to variables are pointers to the byte following the
    //  end of each appropriate buffer.  This saves us from doing the addition
    //  for each loop check
    //

    PUCHAR EndOfUncompressedBuffer = UncompressedBuffer + UncompressedBufferSize;
    PUCHAR EndOfCompressedBuffer = CompressedBuffer + CompressedBufferSize;

    //
    //  Make sure that the compressed buffer is at least four bytes long to
    //  start with, and then get the first chunk header and make sure it
    //  is not an ending chunk header.
    //

    RtlRetrieveUshort( &ChunkHeader, CompressedChunk );

    //
    //  Now while there is space in the uncompressed buffer to store data
    //  we will loop through decompressing chunks
    //

    while (TRUE) {

        CompressedChunkSize = GetCompressedChunkSize(ChunkHeader);

        //
        //  First make sure the chunk contains compressed data
        //

        if (ChunkHeader.Chunk.IsChunkCompressed) {

            //
            //  Decompress a chunk and return if we get an error
            //

            if (!NT_SUCCESS(Status = LZOPTDecompressChunk( UncompressedChunk,
                                                         EndOfUncompressedBuffer,
                                                         CompressedChunk,
                                                         CompressedChunk + CompressedChunkSize,
                                                         &UncompressedChunkSize ))) {

                return Status;
            }

        } else {

            //
            //  The chunk does not contain compressed data so we need to simply
            //  copy over the uncompressed data
            //

            UncompressedChunkSize = GetUncompressedChunkSize( ChunkHeader );

            //
            //  Make sure the data will fit into the output buffer
            //

            if (UncompressedChunk + UncompressedChunkSize > EndOfUncompressedBuffer) {

                UncompressedChunkSize = EndOfUncompressedBuffer - UncompressedChunk;
            }

            RtlCopyMemory( UncompressedChunk,
                           CompressedChunk + sizeof(COMPRESSED_CHUNK_HEADER),
                           UncompressedChunkSize );
        }

        //
        //  Now update the compressed and uncompressed chunk pointers with
        //  the size of the compressed chunk and the number of bytes we
        //  decompressed into, and then make sure we didn't exceed our buffers
        //

        CompressedChunk += CompressedChunkSize;
        UncompressedChunk += UncompressedChunkSize;

        //
        //  Now if the uncompressed is full then we are done
        //

        if (UncompressedChunk == EndOfUncompressedBuffer) { break; }

        //
        //  Otherwise we need to get the next chunk header.  We first
        //  check if there is one, save the old chunk size for the
        //  chunk we just read in, get the new chunk, and then check
        //  if it is the ending chunk header
        //

        if (CompressedChunk > EndOfCompressedBuffer - 2) { break; }

        SavedChunkSize = GetUncompressedChunkSize(ChunkHeader);

        RtlRetrieveUshort( &ChunkHeader, CompressedChunk );
        if (ChunkHeader.Short == 0) { break; }

        //
        //  At this point we are not at the end of the uncompressed buffer
        //  and we have another chunk to process.  But before we go on we
        //  need to see if the last uncompressed chunk didn't fill the full
        //  uncompressed chunk size.
        //

        if (UncompressedChunkSize < SavedChunkSize) {

            LONG t1;
            PUCHAR t2;

            //
            //  Now we only need to zero out data if the really are going
            //  to process another chunk, to test for that we check if
            //  the zero will go beyond the end of the uncompressed buffer
            //

            if ((t2 = (UncompressedChunk +
                       (t1 = (SavedChunkSize -
                              UncompressedChunkSize)))) >= EndOfUncompressedBuffer) {

                break;
            }

            RtlZeroMemory( UncompressedChunk, t1);
            UncompressedChunk = t2;
        }
    }

    //
    //  If we got out of the loop with the compressed chunk pointer beyond the
    //  end of compressed buffer then the compression buffer is ill formed.
    //

    if (CompressedChunk > EndOfCompressedBuffer) { return STATUS_BAD_COMPRESSION_BUFFER; }

    //
    //  The final uncompressed size is the difference between the start of the
    //  uncompressed buffer and where the uncompressed chunk pointer was left
    //

    *FinalUncompressedSize = UncompressedChunk - UncompressedBuffer;

    //
    //  And return to our caller
    //

    return STATUS_SUCCESS;
}
VOID 
HealthBloodPressureServiceContent::BloodPressureMeasurementEvent(
    _In_ BTH_LE_GATT_EVENT_TYPE EventType,
    _In_ PVOID EventOutParameter
    )
{
    HRESULT hr = S_OK;
    PBLUETOOTH_GATT_VALUE_CHANGED_EVENT ValueChangedEventParameters = NULL;
    USHORT temp = 0;
    BLOODPRESSURE_MEASUREMENT Measurement = {0};
    IPortableDeviceValues * pEventParams = NULL;
    BYTE* pBuffer = NULL;
    DWORD cbBuffer = 0;    

    if (CharacteristicValueChangedEvent != EventType) {
        return;
    }

    ValueChangedEventParameters = (PBLUETOOTH_GATT_VALUE_CHANGED_EVENT)EventOutParameter;    

    //
    // Our value is at least 7 bytes long
    //
    if (7 > ValueChangedEventParameters->CharacteristicValue->DataSize) {
        hr = E_FAIL;
        CHECK_HR(hr, "Invalid data size");
    }

    if (SUCCEEDED(hr))
    {

        //
        // The first byte is the Flag field
        //
        Measurement.Flags = ValueChangedEventParameters->CharacteristicValue->Data[0];

        //
        // Systolic
        //
        RtlRetrieveUshort(&temp, &ValueChangedEventParameters->CharacteristicValue->Data[1]);        
        Measurement.Systolic = UshortToFloat(temp);

        //
        // Diastolic
        //
        RtlRetrieveUshort(&temp, &ValueChangedEventParameters->CharacteristicValue->Data[3]);        
        Measurement.Diastolic = UshortToFloat(temp);

        //
        // Mean Arterial Pressure
        //
        RtlRetrieveUshort(&temp, &ValueChangedEventParameters->CharacteristicValue->Data[5]);        
        Measurement.MeanArterialPressure = UshortToFloat(temp);

    }
    
    //
    // Get the timestamp
    //
    if (SUCCEEDED(hr))
    {
        BOOL isTimeProcessed = FALSE;
        //
        // If the time is provided by the BloodPressureMeasurement, use it.
        // If this flag is set, the value must be at least 14 bytes long
        //
        if ((0x02 == (Measurement.Flags & 0x02)) &&
            (14 <= ValueChangedEventParameters->CharacteristicValue->DataSize)) {

            SYSTEMTIME systemTime = {0};
            FILETIME fTime = {0};

            //
            // This value is expressed in the org.bluetooth.characteristic.date_time format.
            //
            
            //
            // Year (2 bytes)
            //
            RtlRetrieveUshort(&temp, &ValueChangedEventParameters->CharacteristicValue->Data[7]);
            systemTime.wYear = temp;            

            //
            // Month (1 byte)
            //
            systemTime.wMonth = ValueChangedEventParameters->CharacteristicValue->Data[9];

            //
            // Day (1 byte)
            //
            systemTime.wDay = ValueChangedEventParameters->CharacteristicValue->Data[10]; 

            //
            // Hours (1 byte)
            //
            systemTime.wHour = ValueChangedEventParameters->CharacteristicValue->Data[11];

            //
            // Minutes (1 byte)
            //
            systemTime.wMinute = ValueChangedEventParameters->CharacteristicValue->Data[12];            

            //
            // Seconds (1 byte)
            //
            systemTime.wSecond = ValueChangedEventParameters->CharacteristicValue->Data[13];

            //
            // Convert into FILETIME
            //
            if (SystemTimeToFileTime(&systemTime, &fTime)) {
                
                ConvertFileTimeToUlonglong(&fTime, &Measurement.TimeStamp);
                isTimeProcessed = TRUE;
            }
        } 

        //
        // If the measurement didn't contain a timestamp or we failed to process it,
        // generate it based on the current time.
        //
        if (!isTimeProcessed) {

            FILETIME fTime;

            GetSystemTimeAsFileTime(&fTime);

            ConvertFileTimeToUlonglong(&fTime, &Measurement.TimeStamp);
        }
        
    }  

    //
    // CoCreate a collection to store the property set event parameters.
    //
    if (SUCCEEDED(hr))
    {
        hr = CoCreateInstance(CLSID_PortableDeviceValues,
                              NULL,
                              CLSCTX_INPROC_SERVER,
                              IID_IPortableDeviceValues,
                              (VOID**) &pEventParams);
        CHECK_HR(hr, "Failed to CoCreateInstance CLSID_PortableDeviceValues");
    }            

    if (SUCCEEDED(hr))
    {    
        hr = pEventParams->SetGuidValue(WPD_EVENT_PARAMETER_EVENT_ID, EVENT_HealthBloodPressureService_Measurement);
        CHECK_HR(hr, "Failed to add WPD_EVENT_PARAMETER_EVENT_ID");
    }

    //
    // Set the timestamp
    //
    if (SUCCEEDED(hr))
    {
        hr = pEventParams->SetUnsignedLargeIntegerValue(EVENT_PARAMETER_HealthBloodPressureService_Measurement_TimeStamp, Measurement.TimeStamp);
        CHECK_HR(hr, "Failed to add EVENT_PARAMETER_HealthBloodPressureService_Measurement_TimeStamp");
    }
    
    //
    // Set the measurement type
    //
    if (SUCCEEDED(hr))
    {
        if (0x01 == (Measurement.Flags & 0x01)) {
            hr = pEventParams->SetStringValue(EVENT_PARAMETER_HealthBloodPressureService_Measurement_Type, L"kPa");
        } else {
            hr = pEventParams->SetStringValue(EVENT_PARAMETER_HealthBloodPressureService_Measurement_Type, L"mmHg");            
        }
        CHECK_HR(hr, "Failed to add EVENT_PARAMETER_HealthBloodPressureService_Measurement_Type");
    }
    
    //
    // Set the Systolic value
    //
    if (SUCCEEDED(hr))
    {
        float ftemp = (float)Measurement.Systolic;
        hr = pEventParams->SetFloatValue(EVENT_PARAMETER_HealthBloodPressureService_Measurement_Systolic, ftemp);
        CHECK_HR(hr, "Failed to add EVENT_PARAMETER_HealthBloodPressureService_Measurement_Systolic");        
    }
    
    //
    // Set the Diastolic value
    //
    if (SUCCEEDED(hr))
    {
        float ftemp = (float)Measurement.Diastolic;    
        hr = pEventParams->SetFloatValue(EVENT_PARAMETER_HealthBloodPressureService_Measurement_Diastolic, ftemp);
        CHECK_HR(hr, "Failed to add EVENT_PARAMETER_HealthBloodPressureService_Measurement_Diastolic");        
    }    
    
    //
    // Set the Mean Arterial Pressure value
    //
    if (SUCCEEDED(hr))
    {
        float ftemp = (float)Measurement.MeanArterialPressure;
        hr = pEventParams->SetFloatValue(EVENT_PARAMETER_HealthBloodPressureService_Measurement_MeanArterialPressure, ftemp);
        CHECK_HR(hr, "Failed to add EVENT_PARAMETER_HealthBloodPressureService_Measurement_MeanArterialPressure");        
    }
    
    //
    // Adding this event parameter will allow WPD to scope this event to the container functional object    
    //
    if (SUCCEEDED(hr))
    {
        hr = pEventParams->SetStringValue(WPD_EVENT_PARAMETER_OBJECT_PARENT_PERSISTENT_UNIQUE_ID, ParentPersistentUniqueID);
        CHECK_HR(hr, "Failed to add WPD_EVENT_PARAMETER_OBJECT_PARENT_PERSISTENT_UNIQUE_ID");
    }

    //
    // Adding this event parameter will allow WPD to scope this event to the container functional object
    //
    if (SUCCEEDED(hr))
    {
        hr = pEventParams->SetStringValue(WPD_OBJECT_CONTAINER_FUNCTIONAL_OBJECT_ID, SERVICE_OBJECT_ID);
        CHECK_HR(hr, "Failed to add WPD_OBJECT_CONTAINER_FUNCTIONAL_OBJECT_ID");
    }
    
    //
    // Create a buffer with the serialized parameters
    //
    if (SUCCEEDED(hr))
    {
        hr = m_pWpdSerializer->GetBufferFromIPortableDeviceValues(pEventParams, &pBuffer, &cbBuffer);
        CHECK_HR(hr, "Failed to get buffer from IPortableDeviceValues");
    }

    if (SUCCEEDED(hr) && NULL == pBuffer)
    {
        hr = E_FAIL;
        CHECK_HR(hr, "pBuffer is NULL");
    }

    //
    // Send the event
    //
    if (SUCCEEDED(hr))
    {
        hr = m_pDevice->PostEvent(WPD_EVENT_NOTIFICATION, WdfEventBroadcast, pBuffer, cbBuffer);
        CHECK_HR(hr, "Failed to post WPD (broadcast) event");
    }
    
    
    //
    // Cleanup
    //
    if (NULL != pBuffer)
    {
        CoTaskMemFree(pBuffer);
        pBuffer = NULL;
    }

    if (NULL != pEventParams)
    {
        pEventParams->Release();
        pEventParams = NULL;
    }
}