public static Object denormalizedValue()

in sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/mdesrc/cryptography/SqlSerializerUtil.java [342:566]


    public static Object denormalizedValue(byte[] decryptedValue, JDBCType jdbcType, SSType ssType, int precision,
                                           int scale, Calendar cal) throws MicrosoftDataEncryptionException {
        Charset charset = null;
        switch (ssType) {
            case CHAR:
            case VARCHAR:
            case NCHAR:
            case NVARCHAR:
            case VARCHARMAX:
            case NVARCHARMAX: {
                try {
                    switch (ssType) {
                        case CHAR:
                        case VARCHAR:
                        case VARCHARMAX:
                            charset = UTF_8;
                            break;
                        case NCHAR:
                        case NVARCHAR:
                        case NVARCHARMAX:
                            charset = UTF_16LE;
                            break;
                        default:
                            // impossible to come here
                            MessageFormat form = new MessageFormat(
                                    MicrosoftDataEncryptionExceptionResource.getResource("R_InvalidDataType"));
                            Object[] msgArgs = {ssType};
                            throw new MicrosoftDataEncryptionException(form.format(msgArgs));
                    }
                    String strVal = new String(decryptedValue, 0, decryptedValue.length, charset);
                    if ((SSType.CHAR == ssType) || (SSType.NCHAR == ssType)) {
                        // Right pad the string for CHAR types.
                        StringBuilder sb = new StringBuilder(strVal);
                        int padLength = precision - strVal.length();
                        for (int i = 0; i < padLength; i++) {
                            sb.append(' ');
                        }
                        strVal = sb.toString();
                    }
                    return convertStringToObject(strVal, jdbcType);
                } catch (IllegalArgumentException e) {
                    MessageFormat form = new MessageFormat(
                            MicrosoftDataEncryptionExceptionResource.getResource("R_InvalidDataType"));
                    Object[] msgArgs = {ssType};
                    throw new MicrosoftDataEncryptionException(form.format(msgArgs));
                } catch (UnsupportedEncodingException e) {
                    MessageFormat form = new MessageFormat(
                            MicrosoftDataEncryptionExceptionResource.getResource("R_InvalidEncoding"));
                    Object[] msgArgs = {charset};
                    throw new MicrosoftDataEncryptionException(form.format(msgArgs));
                }
            }

            case BIT:
            case TINYINT:
            case SMALLINT:
            case INTEGER:
            case BIGINT: {
                // If data is encrypted, then these types are normalized to BIGINT. Need to denormalize here.
                if (8 != decryptedValue.length) {
                    // Integer datatypes are normalized to bigint for AE.
                    MessageFormat form = new MessageFormat(
                            MicrosoftDataEncryptionExceptionResource.getResource("R_InvalidDataType"));
                    Object[] msgArgs = {ssType};
                    throw new MicrosoftDataEncryptionException(form.format(msgArgs));
                }
                return convertLongToObject(readLong(decryptedValue, 0), jdbcType, ssType);

            }

            case REAL:
            case FLOAT: {
                // JDBC driver does not normalize real to float.
                if (8 == decryptedValue.length) {
                    return convertDoubleToObject(
                            ByteBuffer.wrap(decryptedValue).order(ByteOrder.LITTLE_ENDIAN).getDouble(),
                            JDBCType.VARBINARY == jdbcType ? ssType.getJDBCType() : jdbcType);
                } else if (4 == decryptedValue.length) {
                    return convertFloatToObject(
                            ByteBuffer.wrap(decryptedValue).order(ByteOrder.LITTLE_ENDIAN).getFloat(),
                            JDBCType.VARBINARY == jdbcType ? ssType.getJDBCType() : jdbcType);
                } else {
                    MessageFormat form = new MessageFormat(
                            MicrosoftDataEncryptionExceptionResource.getResource("R_InvalidDataType"));
                    Object[] msgArgs = {ssType};
                    throw new MicrosoftDataEncryptionException(form.format(msgArgs));
                }
            }
            case SMALLMONEY: {
                return convertMoneyToObject(new BigDecimal(BigInteger.valueOf(readInt(decryptedValue, 4)), 4),
                        JDBCType.VARBINARY == jdbcType ? ssType.getJDBCType() : jdbcType, 4);
            }

            case MONEY: {
                BigInteger bi = BigInteger.valueOf(
                        ((long) readInt(decryptedValue, 0) << 32) | (readInt(decryptedValue, 4) & 0xFFFFFFFFL));

                return convertMoneyToObject(new BigDecimal(bi, 4),
                        JDBCType.VARBINARY == jdbcType ? ssType.getJDBCType() : jdbcType, 8);
            }

            case NUMERIC:
            case DECIMAL: {
                return convertBigDecimalToObject(readBigDecimal(decryptedValue, decryptedValue.length, scale),
                        JDBCType.VARBINARY == jdbcType ? ssType.getJDBCType() : jdbcType);
            }

            case BINARY:
            case VARBINARY:
            case VARBINARYMAX: {
                return convertBytesToObject(decryptedValue, jdbcType, ssType, precision);
            }

            case DATE: {
                // get the number of days !! Size should be 3
                if (3 != decryptedValue.length) {
                    MessageFormat form = new MessageFormat(
                            MicrosoftDataEncryptionExceptionResource.getResource("R_InvalidDataType"));
                    Object[] msgArgs = {ssType};
                    throw new MicrosoftDataEncryptionException(form.format(msgArgs));
                }

                // Getting number of days
                // Following Lines of code copied from IOBuffer.readDaysIntoCE as we
                // cannot reuse method
                int daysIntoCE = getDaysIntoCE(decryptedValue, ssType);

                return convertTemporalToObject(jdbcType, ssType, cal, daysIntoCE, 0, 0);

            }

            case TIME: {
                long localNanosSinceMidnight = readNanosSinceMidnightAE(decryptedValue, scale, ssType);

                return convertTemporalToObject(jdbcType, SSType.TIME, cal, 0, localNanosSinceMidnight, scale);
            }

            case DATETIME2: {
                if (8 != decryptedValue.length) {
                    MessageFormat form = new MessageFormat(
                            MicrosoftDataEncryptionExceptionResource.getResource("R_InvalidDataType"));
                    Object[] msgArgs = {ssType};
                    throw new MicrosoftDataEncryptionException(form.format(msgArgs));
                }

                // Last three bytes are for date and remaining for time
                int dateOffset = decryptedValue.length - 3;
                byte[] timePortion = new byte[dateOffset];
                byte[] datePortion = new byte[3];
                System.arraycopy(decryptedValue, 0, timePortion, 0, dateOffset);
                System.arraycopy(decryptedValue, dateOffset, datePortion, 0, 3);
                long localNanosSinceMidnight = readNanosSinceMidnightAE(timePortion, scale, ssType);

                int daysIntoCE = getDaysIntoCE(datePortion, ssType);

                // Convert the DATETIME2 value to the desired Java type.
                return convertTemporalToObject(jdbcType, SSType.DATETIME2, cal, daysIntoCE, localNanosSinceMidnight,
                        scale);

            }

            case SMALLDATETIME: {
                if (4 != decryptedValue.length) {
                    MessageFormat form = new MessageFormat(
                            MicrosoftDataEncryptionExceptionResource.getResource("R_InvalidDataType"));
                    Object[] msgArgs = {ssType};
                    throw new MicrosoftDataEncryptionException(form.format(msgArgs));
                }

                // SQL smalldatetime has less precision. It stores 2 bytes
                // for the days since SQL Base Date and 2 bytes for minutes
                // after midnight.
                return convertTemporalToObject(jdbcType, SSType.DATETIME, cal, readUnsignedShort(decryptedValue, 0),
                        readUnsignedShort(decryptedValue, 2) * 60L * 1000L, 0);
            }

            case DATETIME: {
                long ticksSinceMidnight = ((long)readInt(decryptedValue, 4) * 10 + 1) / 3;

                if (8 != decryptedValue.length || Integer.MAX_VALUE < ticksSinceMidnight || ticksSinceMidnight < 0) {
                    MessageFormat form = new MessageFormat(
                            MicrosoftDataEncryptionExceptionResource.getResource("R_InvalidDataType"));
                    Object[] msgArgs = {ssType};
                    throw new MicrosoftDataEncryptionException(form.format(msgArgs));
                }

                // SQL datetime is 4 bytes for days since SQL Base Date
                // (January 1, 1900 00:00:00 GMT) and 4 bytes for
                // the number of three hundredths (1/300) of a second since midnight.
                return convertTemporalToObject(jdbcType, SSType.DATETIME, cal, readInt(decryptedValue, 0),
                        ticksSinceMidnight, 0);
            }

            case DATETIMEOFFSET: {
                // Last 5 bytes are for date and offset
                int dateOffset = decryptedValue.length - 5;
                byte[] timePortion = new byte[dateOffset];
                byte[] datePortion = new byte[3];
                byte[] offsetPortion = new byte[2];
                System.arraycopy(decryptedValue, 0, timePortion, 0, dateOffset);
                System.arraycopy(decryptedValue, dateOffset, datePortion, 0, 3);
                System.arraycopy(decryptedValue, dateOffset + 3, offsetPortion, 0, 2);
                long localNanosSinceMidnight = readNanosSinceMidnightAE(timePortion, scale, ssType);

                int daysIntoCE = getDaysIntoCE(datePortion, ssType);

                int localMinutesOffset = ByteBuffer.wrap(offsetPortion).order(ByteOrder.LITTLE_ENDIAN).getShort();

                return convertTemporalToObject(jdbcType, SSType.DATETIMEOFFSET,
                        new GregorianCalendar(new SimpleTimeZone(localMinutesOffset * 60 * 1000, ""), Locale.US),
                        daysIntoCE, localNanosSinceMidnight, scale);

            }

            case GUID: {
                return readGUID(decryptedValue);
            }

            default:
                MessageFormat form = new MessageFormat(
                        MicrosoftDataEncryptionExceptionResource.getResource("R_InvalidDataType"));
                Object[] msgArgs = {ssType};
                throw new MicrosoftDataEncryptionException(form.format(msgArgs));
        }
    }