1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include "rowinputbinary.hxx" 21 #include <com/sun/star/sdbc/DataType.hpp> 22 #include <com/sun/star/io/WrongFormatException.hpp> 23 #include <com/sun/star/io/XConnectable.hpp> 24 #include <com/sun/star/util/Time.hpp> 25 #include <com/sun/star/util/Date.hpp> 26 #include <com/sun/star/util/DateTime.hpp> 27 28 #include <unotools/ucbstreamhelper.hxx> 29 #include <tools/stream.hxx> 30 #include <rtl/ustrbuf.hxx> 31 32 #include <boost/date_time/posix_time/posix_time.hpp> 33 34 namespace 35 { 36 /** 37 * Converts binary represented big integer value to BCD (Binary Coded 38 * Decimal), and returns a string representation of the number. 39 * 40 * Bytes[0] is the most significant part of the number. 41 */ 42 OUString lcl_double_dabble(const std::vector<sal_uInt8>& bytes) 43 { 44 size_t nbits = 8 * bytes.size(); // length of array in bits 45 size_t nscratch = nbits / 2; // length of scratch in bytes 46 std::vector<char> scratch(nscratch, 0); 47 48 for (size_t i = 0; i < bytes.size(); ++i) 49 { 50 for (size_t j = 0; j < 8; ++j) 51 { 52 /* This bit will be shifted in on the right. */ 53 int shifted_in = (bytes[i] & (1 << (7 - j))) ? 1 : 0; 54 55 /* Add 3 everywhere that scratch[k] >= 5. */ 56 for (size_t k = 0; k < nscratch; ++k) 57 scratch[k] += (scratch[k] >= 5) ? 3 : 0; 58 59 /* Shift scratch to the left by one position. */ 60 for (size_t k = 0; k < nscratch - 1; ++k) 61 { 62 scratch[k] <<= 1; 63 scratch[k] &= 0xF; 64 scratch[k] |= (scratch[k + 1] >= 8) ? 1 : 0; 65 } 66 67 /* Shift in the new bit from arr. */ 68 scratch[nscratch - 1] <<= 1; 69 scratch[nscratch - 1] &= 0xF; 70 scratch[nscratch - 1] |= shifted_in; 71 } 72 } 73 74 auto it = scratch.begin(); 75 /* Remove leading zeros from the scratch space. */ 76 while (*it == 0 && scratch.size() > 1) 77 { 78 it = scratch.erase(it); 79 } 80 81 /* Convert the scratch space from BCD digits to ASCII. */ 82 for (auto& digit : scratch) 83 digit += '0'; 84 85 /* Resize and return the resulting string. */ 86 return OStringToOUString(OString(scratch.data(), scratch.size()), RTL_TEXTENCODING_UTF8); 87 } 88 89 OUString lcl_makeStringFromBigint(const std::vector<sal_uInt8>& bytes) 90 { 91 std::vector<sal_uInt8> aBytes{ bytes }; 92 OUStringBuffer sRet; 93 94 // two's complement 95 if ((aBytes[0] & 0x80) != 0) 96 { 97 sRet.append("-"); 98 for (auto& byte : aBytes) 99 byte = ~byte; 100 // add 1 to byte array 101 // FIXME e.g. 10000 valid ? 102 for (size_t i = aBytes.size() - 1; i != 0; --i) 103 { 104 aBytes[i] += 1; 105 if (aBytes[i] != 0) 106 break; 107 } 108 } 109 // convert binary to BCD 110 OUString sNum = lcl_double_dabble(aBytes); 111 sRet.append(sNum); 112 return sRet.makeStringAndClear(); 113 } 114 115 OUString lcl_putDot(const OUString& sNum, sal_Int32 nScale) 116 { 117 // e.g. sNum = "0", nScale = 2 -> "0.00" 118 OUStringBuffer sBuf{ sNum }; 119 sal_Int32 nNullsToAppend = nScale - sNum.getLength() + 1; 120 for (sal_Int32 i = 0; i < nNullsToAppend; ++i) 121 sBuf.insert(0, "0"); 122 123 if (nScale > 0) 124 sBuf.insert(sBuf.getLength() - 1 - nScale, "."); 125 return sBuf.makeStringAndClear(); 126 } 127 } 128 129 namespace dbahsql 130 { 131 using namespace css::uno; 132 using namespace css::sdbc; 133 using namespace css::io; 134 using namespace boost::posix_time; 135 using namespace boost::gregorian; 136 137 HsqlRowInputStream::HsqlRowInputStream() {} 138 139 void HsqlRowInputStream::setInputStream(Reference<XInputStream> const& rStream) 140 { 141 m_pStream = utl::UcbStreamHelper::CreateStream(rStream, true); 142 m_pStream->SetEndian(SvStreamEndian::BIG); 143 } 144 145 SvStream* HsqlRowInputStream::getInputStream() const { return m_pStream.get(); } 146 147 void HsqlRowInputStream::seek(sal_Int32 nPos) { m_pStream->Seek(nPos); } 148 149 OUString HsqlRowInputStream::readString() 150 { 151 sal_Int32 nLen = 0; 152 m_pStream->ReadInt32(nLen); 153 return readUTF(nLen); 154 } 155 156 OUString HsqlRowInputStream::readUTF(sal_Int32 nUTFLen) 157 { 158 Sequence<sal_Unicode> aBuffer(nUTFLen); 159 sal_Unicode* pStr = aBuffer.getArray(); 160 161 sal_Int32 nCount = 0; 162 sal_Int32 nStrLen = 0; 163 while (nCount < nUTFLen) 164 { 165 unsigned char cIn = 0; 166 m_pStream->ReadUChar(cIn); 167 sal_uInt8 c = reinterpret_cast<sal_uInt8&>(cIn); 168 sal_uInt8 char2, char3; 169 switch (c >> 4) 170 { 171 case 0: 172 case 1: 173 case 2: 174 case 3: 175 case 4: 176 case 5: 177 case 6: 178 case 7: 179 // 0xxxxxxx 180 nCount++; 181 pStr[nStrLen++] = c; 182 break; 183 184 case 12: 185 case 13: 186 // 110x xxxx 10xx xxxx 187 nCount += 2; 188 if (nCount > nUTFLen) 189 { 190 throw WrongFormatException(); 191 } 192 193 m_pStream->ReadUChar(cIn); 194 char2 = reinterpret_cast<sal_uInt8&>(cIn); 195 if ((char2 & 0xC0) != 0x80) 196 { 197 throw WrongFormatException(); 198 } 199 200 pStr[nStrLen++] = (sal_Unicode(c & 0x1F) << 6) | (char2 & 0x3F); 201 break; 202 203 case 14: 204 // 1110 xxxx 10xx xxxx 10xx xxxx 205 nCount += 3; 206 if (nCount > nUTFLen) 207 { 208 throw WrongFormatException(); 209 } 210 211 m_pStream->ReadUChar(cIn); 212 char2 = reinterpret_cast<sal_uInt8&>(cIn); 213 m_pStream->ReadUChar(cIn); 214 char3 = reinterpret_cast<sal_uInt8&>(cIn); 215 216 if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) 217 { 218 throw WrongFormatException(); 219 } 220 pStr[nStrLen++] = (sal_Unicode(c & 0x0F) << 12) | (sal_Unicode(char2 & 0x3F) << 6) 221 | (char3 & 0x3F); 222 break; 223 224 default: 225 // 10xx xxxx, 1111 xxxx 226 throw WrongFormatException(); 227 } 228 } 229 return OUString(pStr, nStrLen); 230 } 231 232 bool HsqlRowInputStream::checkNull() 233 { 234 unsigned char cIn = 0; 235 m_pStream->ReadUChar(cIn); 236 sal_uInt8 nNull = reinterpret_cast<sal_uInt8&>(cIn); 237 return nNull == 0; 238 } 239 240 std::vector<Any> HsqlRowInputStream::readOneRow(const std::vector<ColumnDefinition>& nColTypes) 241 { 242 auto nLen = nColTypes.size(); 243 std::vector<Any> aData; 244 245 for (size_t i = 0; i < nLen; ++i) 246 { 247 if (checkNull()) 248 { 249 aData.push_back(Any()); 250 continue; 251 } 252 253 sal_Int32 nType = nColTypes[i].getDataType(); 254 255 // TODO throw error on EoF 256 257 switch (nType) 258 { 259 case DataType::CHAR: 260 case DataType::VARCHAR: 261 case DataType::LONGVARCHAR: 262 aData.push_back(makeAny(readString())); 263 break; 264 case DataType::TINYINT: 265 case DataType::SMALLINT: 266 { 267 sal_Int16 value = 0; 268 m_pStream->ReadInt16(value); 269 aData.push_back(makeAny(value)); 270 } 271 break; 272 case DataType::INTEGER: 273 { 274 sal_Int32 value = 0; 275 m_pStream->ReadInt32(value); 276 aData.push_back(makeAny(value)); 277 } 278 break; 279 case DataType::BIGINT: 280 { 281 sal_Int64 value = 0; 282 m_pStream->ReadInt64(value); 283 aData.push_back(makeAny(value)); 284 } 285 break; 286 case DataType::REAL: 287 case DataType::FLOAT: 288 case DataType::DOUBLE: 289 { 290 double value = 0; 291 m_pStream->ReadDouble(value); 292 // FIXME double is not necessarily 4 bytes 293 aData.push_back(makeAny(value)); 294 } 295 break; 296 case DataType::NUMERIC: 297 case DataType::DECIMAL: 298 { 299 sal_Int32 nSize = 0; 300 m_pStream->ReadInt32(nSize); 301 302 std::vector<sal_uInt8> aBytes(nSize); 303 m_pStream->ReadBytes(aBytes.data(), nSize); 304 assert(aBytes.size() > 0); 305 306 sal_Int32 nScale = 0; 307 m_pStream->ReadInt32(nScale); 308 309 Sequence<Any> result(2); 310 OUString sNum = lcl_makeStringFromBigint(aBytes); 311 result[0] <<= lcl_putDot(sNum, nScale); 312 result[1] <<= nScale; 313 aData.push_back(makeAny(result)); 314 } 315 break; 316 case DataType::DATE: 317 { 318 sal_Int64 value = 0; 319 m_pStream->ReadInt64(value); // in millisec, from 1970 320 ptime epoch = time_from_string("1970-01-01 00:00:00.000"); 321 ptime time = epoch + milliseconds(value); 322 date asDate = time.date(); 323 324 css::util::Date loDate(asDate.day(), asDate.month(), 325 asDate.year()); // day, month, year 326 aData.push_back(makeAny(loDate)); 327 } 328 break; 329 case DataType::TIME: 330 { 331 sal_Int64 value = 0; 332 m_pStream->ReadInt64(value); 333 auto valueInSecs = value / 1000; 334 /* Observed valueInSecs fall in the range from 335 negative one day to positive two days. Coerce 336 valueInSecs between zero and positive one day.*/ 337 const int secPerDay = 24 * 60 * 60; 338 valueInSecs = (valueInSecs + secPerDay) % secPerDay; 339 340 auto nHours = valueInSecs / (60 * 60); 341 valueInSecs = valueInSecs % 3600; 342 const sal_uInt16 nMins = valueInSecs / 60; 343 const sal_uInt16 nSecs = valueInSecs % 60; 344 css::util::Time time((value % 1000) * 1000000, nSecs, nMins, nHours, true); 345 aData.push_back(makeAny(time)); 346 } 347 break; 348 case DataType::TIMESTAMP: 349 { 350 sal_Int64 nEpochMillis = 0; 351 m_pStream->ReadInt64(nEpochMillis); 352 ptime epoch = time_from_string("1970-01-01 00:00:00.000"); 353 ptime time = epoch + milliseconds(nEpochMillis); 354 date asDate = time.date(); 355 356 sal_Int32 nNanos = 0; 357 m_pStream->ReadInt32(nNanos); 358 359 // convert into LO internal representation of dateTime 360 css::util::DateTime dateTime; 361 dateTime.NanoSeconds = nNanos; 362 dateTime.Seconds = time.time_of_day().seconds(); 363 dateTime.Minutes = time.time_of_day().minutes(); 364 dateTime.Hours = time.time_of_day().hours(); 365 dateTime.Day = asDate.day(); 366 dateTime.Month = asDate.month(); 367 dateTime.Year = asDate.year(); 368 aData.push_back(makeAny(dateTime)); 369 } 370 break; 371 case DataType::BOOLEAN: 372 { 373 sal_uInt8 nBool = 0; 374 m_pStream->ReadUChar(nBool); 375 aData.push_back(makeAny(static_cast<bool>(nBool))); 376 } 377 break; 378 case DataType::OTHER: 379 aData.push_back(Any{}); // TODO 380 break; 381 case DataType::BINARY: 382 case DataType::VARBINARY: 383 case DataType::LONGVARBINARY: 384 { 385 sal_Int32 nSize = 0; 386 m_pStream->ReadInt32(nSize); 387 388 Sequence<sal_Int8> aBytes(nSize); 389 m_pStream->ReadBytes(aBytes.getArray(), nSize); 390 aData.push_back(makeAny(aBytes)); 391 } 392 break; 393 394 default: 395 throw WrongFormatException(); 396 } 397 } 398 return aData; 399 } 400 401 } // namespace dbahsql 402 403 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 404
