LCOV - code coverage report
Current view: top level - libavcodec - hnm4video.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 301 0.0 %
Date: 2017-12-11 04:34:20 Functions: 0 11 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Cryo Interactive Entertainment HNM4 video decoder
       3             :  *
       4             :  * Copyright (c) 2012 David Kment
       5             :  *
       6             :  * This file is part of FFmpeg.
       7             :  *
       8             :  * FFmpeg is free software; you can redistribute it and/or
       9             :  * modify it under the terms of the GNU Lesser General Public
      10             :  * License as published by the Free Software Foundation; either
      11             :  * version 2.1 of the License, or (at your option) any later version.
      12             :  *
      13             :  * FFmpeg is distributed in the hope that it will be useful,
      14             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :  * Lesser General Public License for more details.
      17             :  *
      18             :  * You should have received a copy of the GNU Lesser General Public
      19             :  * License along with FFmpeg; if not, write to the Free Software
      20             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      21             :  */
      22             : 
      23             : #include <string.h>
      24             : 
      25             : #include "libavutil/imgutils.h"
      26             : #include "libavutil/internal.h"
      27             : #include "libavutil/intreadwrite.h"
      28             : #include "libavutil/mem.h"
      29             : #include "avcodec.h"
      30             : #include "bytestream.h"
      31             : #include "internal.h"
      32             : 
      33             : #define HNM4_CHUNK_ID_PL 19536
      34             : #define HNM4_CHUNK_ID_IZ 23113
      35             : #define HNM4_CHUNK_ID_IU 21833
      36             : #define HNM4_CHUNK_ID_SD 17491
      37             : 
      38             : typedef struct Hnm4VideoContext {
      39             :     uint8_t version;
      40             :     int width;
      41             :     int height;
      42             :     uint8_t *current;
      43             :     uint8_t *previous;
      44             :     uint8_t *buffer1;
      45             :     uint8_t *buffer2;
      46             :     uint8_t *processed;
      47             :     uint32_t palette[256];
      48             : } Hnm4VideoContext;
      49             : 
      50           0 : static int getbit(GetByteContext *gb, uint32_t *bitbuf, int *bits)
      51             : {
      52             :     int ret;
      53             : 
      54           0 :     if (!*bits) {
      55           0 :         *bitbuf = bytestream2_get_le32(gb);
      56           0 :         *bits = 32;
      57             :     }
      58             : 
      59           0 :     ret = *bitbuf >> 31;
      60           0 :     *bitbuf <<= 1;
      61           0 :     (*bits)--;
      62             : 
      63           0 :     return ret;
      64             : }
      65             : 
      66           0 : static void unpack_intraframe(AVCodecContext *avctx, uint8_t *src,
      67             :                               uint32_t size)
      68             : {
      69           0 :     Hnm4VideoContext *hnm = avctx->priv_data;
      70             :     GetByteContext gb;
      71           0 :     uint32_t bitbuf = 0, writeoffset = 0, count = 0;
      72             :     uint16_t word;
      73             :     int32_t offset;
      74           0 :     int bits = 0;
      75             : 
      76           0 :     bytestream2_init(&gb, src, size);
      77             : 
      78           0 :     while (bytestream2_tell(&gb) < size) {
      79           0 :         if (getbit(&gb, &bitbuf, &bits)) {
      80           0 :             if (writeoffset >= hnm->width * hnm->height) {
      81           0 :                 av_log(avctx, AV_LOG_ERROR,
      82             :                        "Attempting to write out of bounds\n");
      83           0 :                 break;
      84             :             }
      85           0 :             hnm->current[writeoffset++] = bytestream2_get_byte(&gb);
      86             :         } else {
      87           0 :             if (getbit(&gb, &bitbuf, &bits)) {
      88           0 :                 word   = bytestream2_get_le16(&gb);
      89           0 :                 count  = word & 0x07;
      90           0 :                 offset = (word >> 3) - 0x2000;
      91           0 :                 if (!count)
      92           0 :                     count = bytestream2_get_byte(&gb);
      93           0 :                 if (!count)
      94           0 :                     return;
      95             :             } else {
      96           0 :                 count  = getbit(&gb, &bitbuf, &bits) * 2;
      97           0 :                 count += getbit(&gb, &bitbuf, &bits);
      98           0 :                 offset = bytestream2_get_byte(&gb) - 0x0100;
      99             :             }
     100           0 :             count  += 2;
     101           0 :             offset += writeoffset;
     102           0 :             if (offset < 0 || offset + count >= hnm->width * hnm->height) {
     103           0 :                 av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
     104           0 :                 break;
     105           0 :             } else if (writeoffset + count >= hnm->width * hnm->height) {
     106           0 :                 av_log(avctx, AV_LOG_ERROR,
     107             :                        "Attempting to write out of bounds\n");
     108           0 :                 break;
     109             :             }
     110           0 :             while (count--) {
     111           0 :                 hnm->current[writeoffset++] = hnm->current[offset++];
     112             :             }
     113             :         }
     114             :     }
     115             : }
     116             : 
     117           0 : static void postprocess_current_frame(AVCodecContext *avctx)
     118             : {
     119           0 :     Hnm4VideoContext *hnm = avctx->priv_data;
     120             :     uint32_t x, y, src_x, src_y;
     121             : 
     122           0 :     for (y = 0; y < hnm->height; y++) {
     123           0 :         src_y = y - (y % 2);
     124           0 :         src_x = src_y * hnm->width + (y % 2);
     125           0 :         for (x = 0; x < hnm->width; x++) {
     126           0 :             hnm->processed[(y * hnm->width) + x] = hnm->current[src_x];
     127           0 :             src_x += 2;
     128             :         }
     129             :     }
     130           0 : }
     131             : 
     132           0 : static void copy_processed_frame(AVCodecContext *avctx, AVFrame *frame)
     133             : {
     134           0 :     Hnm4VideoContext *hnm = avctx->priv_data;
     135           0 :     uint8_t *src = hnm->processed;
     136           0 :     uint8_t *dst = frame->data[0];
     137             :     int y;
     138             : 
     139           0 :     for (y = 0; y < hnm->height; y++) {
     140           0 :         memcpy(dst, src, hnm->width);
     141           0 :         src += hnm->width;
     142           0 :         dst += frame->linesize[0];
     143             :     }
     144           0 : }
     145             : 
     146           0 : static void decode_interframe_v4(AVCodecContext *avctx, uint8_t *src, uint32_t size)
     147             : {
     148           0 :     Hnm4VideoContext *hnm = avctx->priv_data;
     149             :     GetByteContext gb;
     150           0 :     uint32_t writeoffset = 0;
     151             :     int count, left, offset;
     152             :     uint8_t tag, previous, backline, backward, swap;
     153             : 
     154           0 :     bytestream2_init(&gb, src, size);
     155             : 
     156           0 :     while (bytestream2_tell(&gb) < size) {
     157           0 :         count = bytestream2_peek_byte(&gb) & 0x1F;
     158           0 :         if (count == 0) {
     159           0 :             tag = bytestream2_get_byte(&gb) & 0xE0;
     160           0 :             tag = tag >> 5;
     161             : 
     162           0 :             if (tag == 0) {
     163           0 :                 if (writeoffset + 2 > hnm->width * hnm->height) {
     164           0 :                     av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n");
     165           0 :                     break;
     166             :                 }
     167           0 :                 hnm->current[writeoffset++] = bytestream2_get_byte(&gb);
     168           0 :                 hnm->current[writeoffset++] = bytestream2_get_byte(&gb);
     169           0 :             } else if (tag == 1) {
     170           0 :                 writeoffset += bytestream2_get_byte(&gb) * 2;
     171           0 :             } else if (tag == 2) {
     172           0 :                 count = bytestream2_get_le16(&gb);
     173           0 :                 count *= 2;
     174           0 :                 writeoffset += count;
     175           0 :             } else if (tag == 3) {
     176           0 :                 count = bytestream2_get_byte(&gb) * 2;
     177           0 :                 if (writeoffset + count > hnm->width * hnm->height) {
     178           0 :                     av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n");
     179           0 :                     break;
     180             :                 }
     181           0 :                 while (count > 0) {
     182           0 :                     hnm->current[writeoffset++] = bytestream2_peek_byte(&gb);
     183           0 :                     count--;
     184             :                 }
     185           0 :                 bytestream2_skip(&gb, 1);
     186             :             } else {
     187           0 :                 break;
     188             :             }
     189           0 :             if (writeoffset > hnm->width * hnm->height) {
     190           0 :                 av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n");
     191           0 :                 break;
     192             :             }
     193             :         } else {
     194           0 :             previous = bytestream2_peek_byte(&gb) & 0x20;
     195           0 :             backline = bytestream2_peek_byte(&gb) & 0x40;
     196           0 :             backward = bytestream2_peek_byte(&gb) & 0x80;
     197           0 :             bytestream2_skip(&gb, 1);
     198           0 :             swap   = bytestream2_peek_byte(&gb) & 0x01;
     199           0 :             offset = bytestream2_get_le16(&gb);
     200           0 :             offset = (offset >> 1) & 0x7FFF;
     201           0 :             offset = writeoffset + (offset * 2) - 0x8000;
     202             : 
     203           0 :             left = count;
     204             : 
     205           0 :             if (!backward && offset + 2*count > hnm->width * hnm->height) {
     206           0 :                 av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
     207           0 :                 break;
     208           0 :             } else if (backward && offset + 1 >= hnm->width * hnm->height) {
     209           0 :                 av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
     210           0 :                 break;
     211           0 :             } else if (writeoffset + 2*count > hnm->width * hnm->height) {
     212           0 :                 av_log(avctx, AV_LOG_ERROR,
     213             :                        "Attempting to write out of bounds\n");
     214           0 :                 break;
     215             :             }
     216           0 :             if(backward) {
     217           0 :                 if (offset < (!!backline)*(2 * hnm->width - 1) + 2*(left-1)) {
     218           0 :                     av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
     219           0 :                     break;
     220             :                 }
     221             :             } else {
     222           0 :                 if (offset < (!!backline)*(2 * hnm->width - 1)) {
     223           0 :                     av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
     224           0 :                     break;
     225             :                 }
     226             :             }
     227             : 
     228           0 :             if (previous) {
     229           0 :                 while (left > 0) {
     230           0 :                     if (backline) {
     231           0 :                         hnm->current[writeoffset++] = hnm->previous[offset - (2 * hnm->width) + 1];
     232           0 :                         hnm->current[writeoffset++] = hnm->previous[offset++];
     233           0 :                         offset++;
     234             :                     } else {
     235           0 :                         hnm->current[writeoffset++] = hnm->previous[offset++];
     236           0 :                         hnm->current[writeoffset++] = hnm->previous[offset++];
     237             :                     }
     238           0 :                     if (backward)
     239           0 :                         offset -= 4;
     240           0 :                     left--;
     241             :                 }
     242             :             } else {
     243           0 :                 while (left > 0) {
     244           0 :                     if (backline) {
     245           0 :                         hnm->current[writeoffset++] = hnm->current[offset - (2 * hnm->width) + 1];
     246           0 :                         hnm->current[writeoffset++] = hnm->current[offset++];
     247           0 :                         offset++;
     248             :                     } else {
     249           0 :                         hnm->current[writeoffset++] = hnm->current[offset++];
     250           0 :                         hnm->current[writeoffset++] = hnm->current[offset++];
     251             :                     }
     252           0 :                     if (backward)
     253           0 :                         offset -= 4;
     254           0 :                     left--;
     255             :                 }
     256             :             }
     257             : 
     258           0 :             if (swap) {
     259           0 :                 left         = count;
     260           0 :                 writeoffset -= count * 2;
     261           0 :                 while (left > 0) {
     262           0 :                     swap = hnm->current[writeoffset];
     263           0 :                     hnm->current[writeoffset] = hnm->current[writeoffset + 1];
     264           0 :                     hnm->current[writeoffset + 1] = swap;
     265           0 :                     left--;
     266           0 :                     writeoffset += 2;
     267             :                 }
     268             :             }
     269             :         }
     270             :     }
     271           0 : }
     272             : 
     273           0 : static void decode_interframe_v4a(AVCodecContext *avctx, uint8_t *src,
     274             :                                   uint32_t size)
     275             : {
     276           0 :     Hnm4VideoContext *hnm = avctx->priv_data;
     277             :     GetByteContext gb;
     278           0 :     uint32_t writeoffset = 0, offset;
     279             :     uint8_t tag, count, previous, delta;
     280             : 
     281           0 :     bytestream2_init(&gb, src, size);
     282             : 
     283           0 :     while (bytestream2_tell(&gb) < size) {
     284           0 :         count = bytestream2_peek_byte(&gb) & 0x3F;
     285           0 :         if (count == 0) {
     286           0 :             tag = bytestream2_get_byte(&gb) & 0xC0;
     287           0 :             tag = tag >> 6;
     288           0 :             if (tag == 0) {
     289           0 :                 writeoffset += bytestream2_get_byte(&gb);
     290           0 :             } else if (tag == 1) {
     291           0 :                 if (writeoffset + hnm->width >= hnm->width * hnm->height) {
     292           0 :                     av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n");
     293           0 :                     break;
     294             :                 }
     295           0 :                 hnm->current[writeoffset]              = bytestream2_get_byte(&gb);
     296           0 :                 hnm->current[writeoffset + hnm->width] = bytestream2_get_byte(&gb);
     297           0 :                 writeoffset++;
     298           0 :             } else if (tag == 2) {
     299           0 :                 writeoffset += hnm->width;
     300           0 :             } else if (tag == 3) {
     301           0 :                 break;
     302             :             }
     303           0 :             if (writeoffset > hnm->width * hnm->height) {
     304           0 :                 av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n");
     305           0 :                 break;
     306             :             }
     307             :         } else {
     308           0 :             delta    = bytestream2_peek_byte(&gb) & 0x80;
     309           0 :             previous = bytestream2_peek_byte(&gb) & 0x40;
     310           0 :             bytestream2_skip(&gb, 1);
     311             : 
     312           0 :             offset  = writeoffset;
     313           0 :             offset += bytestream2_get_le16(&gb);
     314             : 
     315           0 :             if (delta) {
     316           0 :                 if (offset < 0x10000) {
     317           0 :                     av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
     318           0 :                     break;
     319             :                 }
     320           0 :                 offset -= 0x10000;
     321             :             }
     322             : 
     323           0 :             if (offset + hnm->width + count >= hnm->width * hnm->height) {
     324           0 :                 av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
     325           0 :                 break;
     326           0 :             } else if (writeoffset + hnm->width + count >= hnm->width * hnm->height) {
     327           0 :                 av_log(avctx, AV_LOG_ERROR, "Attempting to write out of bounds\n");
     328           0 :                 break;
     329             :             }
     330             : 
     331           0 :             if (previous) {
     332           0 :                 while (count > 0) {
     333           0 :                     hnm->current[writeoffset]              = hnm->previous[offset];
     334           0 :                     hnm->current[writeoffset + hnm->width] = hnm->previous[offset + hnm->width];
     335           0 :                     writeoffset++;
     336           0 :                     offset++;
     337           0 :                     count--;
     338             :                 }
     339             :             } else {
     340           0 :                 while (count > 0) {
     341           0 :                     hnm->current[writeoffset]              = hnm->current[offset];
     342           0 :                     hnm->current[writeoffset + hnm->width] = hnm->current[offset + hnm->width];
     343           0 :                     writeoffset++;
     344           0 :                     offset++;
     345           0 :                     count--;
     346             :                 }
     347             :             }
     348             :         }
     349             :     }
     350           0 : }
     351             : 
     352           0 : static void hnm_update_palette(AVCodecContext *avctx, uint8_t *src,
     353             :                                uint32_t size)
     354             : {
     355           0 :     Hnm4VideoContext *hnm = avctx->priv_data;
     356             :     GetByteContext gb;
     357             :     uint8_t start, writeoffset;
     358             :     uint16_t count;
     359             :     int eight_bit_colors;
     360             : 
     361           0 :     eight_bit_colors = src[7] & 0x80 && hnm->version == 0x4a;
     362             : 
     363             :     // skip first 8 bytes
     364           0 :     bytestream2_init(&gb, src + 8, size - 8);
     365             : 
     366           0 :     while (bytestream2_tell(&gb) < size - 8) {
     367           0 :         start = bytestream2_get_byte(&gb);
     368           0 :         count = bytestream2_get_byte(&gb);
     369           0 :         if (start == 255 && count == 255)
     370           0 :             break;
     371           0 :         if (count == 0)
     372           0 :             count = 256;
     373           0 :         writeoffset = start;
     374           0 :         while (count > 0) {
     375           0 :             hnm->palette[writeoffset] = bytestream2_get_be24(&gb);
     376           0 :             if (!eight_bit_colors)
     377           0 :                 hnm->palette[writeoffset] <<= 2;
     378           0 :             count--;
     379           0 :             writeoffset++;
     380             :         }
     381             :     }
     382           0 : }
     383             : 
     384           0 : static void hnm_flip_buffers(Hnm4VideoContext *hnm)
     385             : {
     386             :     uint8_t *temp;
     387             : 
     388           0 :     temp          = hnm->current;
     389           0 :     hnm->current  = hnm->previous;
     390           0 :     hnm->previous = temp;
     391           0 : }
     392             : 
     393           0 : static int hnm_decode_frame(AVCodecContext *avctx, void *data,
     394             :                             int *got_frame, AVPacket *avpkt)
     395             : {
     396           0 :     AVFrame *frame = data;
     397           0 :     Hnm4VideoContext *hnm = avctx->priv_data;
     398             :     int ret;
     399             :     uint16_t chunk_id;
     400             : 
     401           0 :     if (avpkt->size < 8) {
     402           0 :         av_log(avctx, AV_LOG_ERROR, "packet too small\n");
     403           0 :         return AVERROR_INVALIDDATA;
     404             :     }
     405             : 
     406           0 :     chunk_id = AV_RL16(avpkt->data + 4);
     407             : 
     408           0 :     if (chunk_id == HNM4_CHUNK_ID_PL) {
     409           0 :         hnm_update_palette(avctx, avpkt->data, avpkt->size);
     410           0 :     } else if (chunk_id == HNM4_CHUNK_ID_IZ) {
     411           0 :         if (avpkt->size < 12) {
     412           0 :             av_log(avctx, AV_LOG_ERROR, "packet too small\n");
     413           0 :             return AVERROR_INVALIDDATA;
     414             :         }
     415           0 :         if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
     416           0 :             return ret;
     417             : 
     418           0 :         unpack_intraframe(avctx, avpkt->data + 12, avpkt->size - 12);
     419           0 :         memcpy(hnm->previous, hnm->current, hnm->width * hnm->height);
     420           0 :         if (hnm->version == 0x4a)
     421           0 :             memcpy(hnm->processed, hnm->current, hnm->width * hnm->height);
     422             :         else
     423           0 :             postprocess_current_frame(avctx);
     424           0 :         copy_processed_frame(avctx, frame);
     425           0 :         frame->pict_type = AV_PICTURE_TYPE_I;
     426           0 :         frame->key_frame = 1;
     427           0 :         memcpy(frame->data[1], hnm->palette, 256 * 4);
     428           0 :         *got_frame = 1;
     429           0 :     } else if (chunk_id == HNM4_CHUNK_ID_IU) {
     430           0 :         if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
     431           0 :             return ret;
     432             : 
     433           0 :         if (hnm->version == 0x4a) {
     434           0 :             decode_interframe_v4a(avctx, avpkt->data + 8, avpkt->size - 8);
     435           0 :             memcpy(hnm->processed, hnm->current, hnm->width * hnm->height);
     436             :         } else {
     437           0 :             decode_interframe_v4(avctx, avpkt->data + 8, avpkt->size - 8);
     438           0 :             postprocess_current_frame(avctx);
     439             :         }
     440           0 :         copy_processed_frame(avctx, frame);
     441           0 :         frame->pict_type = AV_PICTURE_TYPE_P;
     442           0 :         frame->key_frame = 0;
     443           0 :         memcpy(frame->data[1], hnm->palette, 256 * 4);
     444           0 :         *got_frame = 1;
     445           0 :         hnm_flip_buffers(hnm);
     446             :     } else {
     447           0 :         av_log(avctx, AV_LOG_ERROR, "invalid chunk id: %d\n", chunk_id);
     448           0 :         return AVERROR_INVALIDDATA;
     449             :     }
     450             : 
     451           0 :     return avpkt->size;
     452             : }
     453             : 
     454           0 : static av_cold int hnm_decode_init(AVCodecContext *avctx)
     455             : {
     456           0 :     Hnm4VideoContext *hnm = avctx->priv_data;
     457             :     int ret;
     458             : 
     459           0 :     if (avctx->extradata_size < 1) {
     460           0 :         av_log(avctx, AV_LOG_ERROR,
     461             :                "Extradata missing, decoder requires version number\n");
     462           0 :         return AVERROR_INVALIDDATA;
     463             :     }
     464             : 
     465           0 :     ret = av_image_check_size(avctx->width, avctx->height, 0, avctx);
     466           0 :     if (ret < 0)
     467           0 :         return ret;
     468             : 
     469           0 :     hnm->version   = avctx->extradata[0];
     470           0 :     avctx->pix_fmt = AV_PIX_FMT_PAL8;
     471           0 :     hnm->width     = avctx->width;
     472           0 :     hnm->height    = avctx->height;
     473           0 :     hnm->buffer1   = av_mallocz(avctx->width * avctx->height);
     474           0 :     hnm->buffer2   = av_mallocz(avctx->width * avctx->height);
     475           0 :     hnm->processed = av_mallocz(avctx->width * avctx->height);
     476             : 
     477           0 :     if (   !hnm->buffer1 || !hnm->buffer2 || !hnm->processed
     478           0 :         || avctx->width * avctx->height == 0
     479           0 :         || avctx->height % 2) {
     480           0 :         av_log(avctx, AV_LOG_ERROR, "av_mallocz() failed\n");
     481           0 :         av_freep(&hnm->buffer1);
     482           0 :         av_freep(&hnm->buffer2);
     483           0 :         av_freep(&hnm->processed);
     484           0 :         return AVERROR(ENOMEM);
     485             :     }
     486             : 
     487           0 :     hnm->current  = hnm->buffer1;
     488           0 :     hnm->previous = hnm->buffer2;
     489             : 
     490           0 :     return 0;
     491             : }
     492             : 
     493           0 : static av_cold int hnm_decode_end(AVCodecContext *avctx)
     494             : {
     495           0 :     Hnm4VideoContext *hnm = avctx->priv_data;
     496             : 
     497           0 :     av_freep(&hnm->buffer1);
     498           0 :     av_freep(&hnm->buffer2);
     499           0 :     av_freep(&hnm->processed);
     500             : 
     501           0 :     return 0;
     502             : }
     503             : 
     504             : AVCodec ff_hnm4_video_decoder = {
     505             :     .name           = "hnm4video",
     506             :     .long_name      = NULL_IF_CONFIG_SMALL("HNM 4 video"),
     507             :     .type           = AVMEDIA_TYPE_VIDEO,
     508             :     .id             = AV_CODEC_ID_HNM4_VIDEO,
     509             :     .priv_data_size = sizeof(Hnm4VideoContext),
     510             :     .init           = hnm_decode_init,
     511             :     .close          = hnm_decode_end,
     512             :     .decode         = hnm_decode_frame,
     513             :     .capabilities   = AV_CODEC_CAP_DR1,
     514             : };

Generated by: LCOV version 1.13