blob: 962564b6cd897566272a5eb4dec92c9382789346 [file] [log] [blame]
/*
* Copyright (c) 2017, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <array>
#include "JsonSerializeHelper.h"
JsonSerializeHelper::JsonSerializeHelper(std::ostream& os) : m_os(os)
{
StartSerialization();
}
JsonSerializeHelper::~JsonSerializeHelper()
{
FinishSerialization();
}
void JsonSerializeHelper::Serialize(const char* key, const std::string& value)
{
Serialize(key, value.c_str());
}
void JsonSerializeHelper::Serialize(const char* key, const char* value)
{
// last comma is overriden during Finish
m_os << R"_(")_" << key << R"_(":")_" << value << R"_(",)_";
}
void JsonSerializeHelper::Serialize(const char* key, const unsigned long long value)
{
// last comma is overriden during Finish
m_os << R"_(")_" << key << R"_(":)_" << value << ",";
}
// Serialization service for composite member that implements the JsonSerializable interface
void JsonSerializeHelper::SerializeComposite(const char* key, const JsonSerializable& value)
{
// last comma is overriden during Finish
m_os << R"_(")_" << key << R"_(":)_";
value.ToJson(m_os);
m_os << ",";
}
void JsonSerializeHelper::SerializeCompositeArray(const char* key, const std::vector<std::unique_ptr<JsonSerializable>>& values)
{
m_os << R"_(")_" << key << R"_(":[)_";
bool first = true;
for (auto & val : values)
{
if (!first) {
m_os << ",";
}
first = false;
if (val)
{
val->ToJson(m_os);
}
else
{
LOG_ERROR << "Got uninitialized vector. key is " << key << std::endl;
}
}
m_os << "],";
}
// Encode given binary array as Base64 string
std::string JsonSerializeHelper::Base64Encode(const std::vector<unsigned char>& binaryData)
{
return Base64Encode(binaryData.data(), binaryData.size());
}
std::string JsonSerializeHelper::Base64Encode(const unsigned char binaryData[], unsigned length)
{
static const std::string base64Vocabulary = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
std::string result;
if (length == 0U)
{
return result;
}
// reserve room for the result (next higher multiple of 3, div by 3, mult by 4)
unsigned mod3 = length % 3;
result.reserve((length + (mod3 ? 3 - mod3 : 0)) * 4 / 3);
int val1 = 0, val2 = -6;
for (unsigned i = 0U; i < length; ++i)
{
val1 = (val1 << 8) + static_cast<int>(binaryData[i]);
val2 += 8;
while (val2 >= 0)
{
result.push_back(base64Vocabulary[(val1 >> val2) & 0x3F]);
val2 -= 6;
}
}
if (val2 > -6)
{
result.push_back(base64Vocabulary[((val1 << 8) >> (val2 + 8)) & 0x3F]);
}
while (result.size() % 4)
{
result.push_back('=');
}
return result;
}
bool JsonSerializeHelper::Base64Decode(const std::string& base64Data, std::vector<unsigned char>& binaryData)
{
static const unsigned char lookup[] =
{
62, 255, 62, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255,
255, 0, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
255, 255, 255, 255, 63, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
};
binaryData.clear();
if (base64Data.empty())
{
return false;
}
binaryData.reserve(base64Data.size() * 3 / 4);
int val1 = 0, val2 = -8;
for (auto c : base64Data)
{
if (c < '+' || c > 'z')
{
break;
}
int mappedVal = static_cast<int>(lookup[c - '+']);
if (mappedVal >= 64)
{
break;
}
val1 = (val1 << 6) + mappedVal;
val2 += 6;
if (val2 >= 0)
{
binaryData.push_back(char((val1 >> val2) & 0xFF));
val2 -= 8;
}
}
return true;
}