Usermode/libimage_sif - Added endian-flipping support
[tpg/acess2.git] / Usermode / Libraries / libimage_sif.so_src / main.c
1 /*
2  */
3 #include <stdint.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include <image.h>
8 //#include <image_sif.h>
9 #include <acess/sys.h>  // _SysDebug
10
11 #define _SysDebug(...)  do{}while(0)
12
13 // === STRUCTURES ===
14 struct sHeader
15 {
16         uint16_t        Magic;
17         uint16_t        Flags;
18         uint16_t        Width;
19         uint16_t        Height;
20 };
21
22 // === CONSTANTS ===
23
24 // === CODE ===
25 int SoMain(void)
26 {
27         return 0;
28 }
29
30 static uint32_t flipendian32(uint32_t val)
31 {
32         return    ((val >> 24) & 0xFF) <<  0
33                 | ((val >> 16) & 0xFF) <<  8
34                 | ((val >>  8) & 0xFF) << 16
35                 | ((val >>  0) & 0xFF) << 24;
36 }
37
38 static void flip_buffer_endian(void *Data, size_t SampleSize, size_t Pixels)
39 {
40         if( SampleSize == 3 )
41                 return ;
42         
43         if( SampleSize == 4 )
44         {
45                 uint32_t *data32 = Data;
46                 while( Pixels -- ) {
47                         *data32 = flipendian32(*data32);
48                         data32 ++;
49                 }
50         }
51 }
52
53 /**
54  */
55 tImage *Image_SIF_Parse(void *Buffer, size_t Size)
56 {
57         uint16_t        w, h;
58          int    ofs, i;
59         tImage  *ret;
60          int    bRevOrder;
61          int    fileOfs = 0;
62          int    comp, fmt;
63          int    sampleSize;
64         struct sHeader  *hdr = Buffer;
65          
66         _SysDebug("Image_SIF_Parse: (Buffer=%p, Size=0x%x)", Buffer, Size);
67         
68         // Get magic word and determine byte ordering
69         if(hdr->Magic == 0x51F0)        // Little Endian
70                 bRevOrder = 0;
71         else if(hdr->Magic == 0xF051)   // Big Endian
72                 bRevOrder = 1;
73         else {
74                 _SysDebug(" Image_SIF_Parse: Magic invalid (0x%x)", hdr->Magic);
75                 return NULL;
76         }
77         
78         _SysDebug(" Image_SIF_Parse: bRevOrder = %i", bRevOrder);
79         
80         // Read flags
81         comp = hdr->Flags & 7;
82         fmt = (hdr->Flags >> 3) & 7;
83         
84         // Read dimensions
85         w = hdr->Width;
86         h = hdr->Height;
87         
88         _SysDebug(" Image_SIF_Parse: Dimensions %ix%i", w, h);
89         
90         // Get image format
91         switch(fmt)
92         {
93         case 0: // ARGB 32-bit Little Endian
94                 fmt = IMGFMT_BGRA;
95                 sampleSize = 4;
96                 break;
97         case 1: // RGB 24-bit big endian
98                 fmt = IMGFMT_RGB;
99                 sampleSize = 3;
100                 break;
101         default:
102                 return NULL;
103         }
104         
105         _SysDebug(" Image_SIF_Parse: sampleSize = %i, fmt = %i", sampleSize, fmt);
106         
107         fileOfs = sizeof(struct sHeader);
108         
109         // Allocate space
110         ret = calloc(1, sizeof(tImage) + w * h * sampleSize);
111         ret->Width = w;
112         ret->Height = h;
113         ret->Format = fmt;
114         for( ofs = 0; ofs < w*h*sampleSize; ofs ++ )
115                 ret->Data[ofs] = 255;
116         
117         switch(comp)
118         {
119         // Uncompressed 32-bpp data
120         case 0: {
121                 size_t  idatsize = w*h*sampleSize;
122                 if( idatsize > Size - fileOfs )
123                         idatsize = Size - fileOfs;
124                 memcpy(ret->Data, Buffer+fileOfs, idatsize);
125                 if(bRevOrder)
126                         flip_buffer_endian(ret->Data, sampleSize, w*h);
127                 return ret;
128                 }
129         
130         // 1.7.n*8 RLE
131         // (1 Flag, 7-bit size, 32-bit value)
132         case 1:
133                 ofs = 0;
134                 while( ofs < w*h*sampleSize )
135                 {
136                         uint8_t len;
137                         if( fileOfs + 1 > Size )
138                                 return ret;
139                         len = ((uint8_t*)Buffer)[fileOfs++];
140                         // Verbatim
141                         if(len & 0x80) {
142                                 len &= 0x7F;
143                                 while( len -- )
144                                 {
145                                         if( fileOfs + sampleSize > Size )
146                                                 return ret;
147                                         memcpy(ret->Data+ofs, Buffer+fileOfs, sampleSize);
148                                         ofs += sampleSize;
149                                         fileOfs += sampleSize;
150                                 }
151                         }
152                         // RLE
153                         else {
154                                 if( fileOfs + sampleSize > Size )
155                                         return ret;
156                                 
157                                 while( len -- )
158                                 {
159                                         memcpy(ret->Data+ofs, Buffer+fileOfs, sampleSize);
160                                         ofs += sampleSize;
161                                 }
162                                 fileOfs += sampleSize;
163                         }
164                 }
165                 if(bRevOrder)
166                         flip_buffer_endian(ret->Data, sampleSize, w*h);
167                 _SysDebug("Image_SIF_Parse: Complete at %i bytes", fileOfs);
168                 return ret;
169         
170         // Channel 1.7.8 RLE
171         // - Each channel is separately 1.7 RLE compressed
172         case 3:
173                 // Alpha, Red, Green, Blue
174                 for( i = 0; i < sampleSize; i++ )
175                 {
176                         ofs = i;
177                         while( ofs < w*h*sampleSize )
178                         {
179                                 uint8_t len, val;
180                                 if( fileOfs + 1 > Size )        return ret;
181                                 len = ((uint8_t*)Buffer)[fileOfs++];
182                                 if(len & 0x80) {
183                                         len &= 0x7F;
184                                         while(len--) {
185                                                 if( fileOfs + 1 > Size )        return ret;
186                                                 val = ((uint8_t*)Buffer)[fileOfs++];
187                                                 ret->Data[ofs] = val;
188                                                 ofs += sampleSize;
189                                         }
190                                 }
191                                 else {
192                                         if( fileOfs + 1 > Size )        return ret;
193                                         val = ((uint8_t*)Buffer)[fileOfs++];
194                                         while(len--) {
195                                                 ret->Data[ofs] = val;
196                                                 ofs += sampleSize;
197                                         }
198                                 }
199                         }
200                 }
201                 return ret;
202         
203         default:
204                 fprintf(stderr, "Warning: Unknown compression scheme %i for SIF\n", comp);
205                 return NULL;
206         }
207 }

UCC git Repository :: git.ucc.asn.au