Kernel/drvutil - Fixes to cursor handling
[tpg/acess2.git] / Kernel / drvutil.c
1 /*
2  * Acess2 Kernel
3  * - By John Hodge
4  *
5  * drvutil.c
6  * - Common Driver/Filesystem Helper Functions
7  */
8 #define DEBUG   0
9 #include <acess.h>
10 #include <api_drv_disk.h>
11 #include <api_drv_video.h>
12
13 // === TYPES ===
14
15 // === PROTOTYPES ===
16 //int   DrvUtil_Video_2DStream(void *Ent, void *Buffer, int Length, tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers);
17 //size_t        DrvUtil_Video_WriteLFB(int Mode, tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, void *Src);
18 //void  DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap);
19 //void  DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y);
20 void    DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf);
21 //void  DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf);
22 void    DrvUtil_Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);
23 void    DrvUtil_Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H);
24
25 // === GLOBALS ===
26 tDrvUtil_Video_2DHandlers       gDrvUtil_Stub_2DFunctions = {
27         NULL,
28         DrvUtil_Video_2D_Fill,
29         DrvUtil_Video_2D_Blit
30 };
31 tVideo_IOCtl_Bitmap     gDrvUtil_TextModeCursor = {
32         8, 16,
33         0, 0,
34         {
35                 0, 0, 0         , 0, 0, 0, 0, 0,
36                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
37                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
38                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
39                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
40                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
41                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
42                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
43                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
44                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
45                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
46                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
47                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
48                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
49                 0, 0, 0         , 0, 0, 0, 0, 0,
50                 0, 0, 0         , 0, 0, 0, 0, 0
51         }
52 };
53
54 // === CODE ===
55 // --- Video Driver Helpers ---
56 int DrvUtil_Video_2DStream(void *Ent, void *Buffer, int Length,
57         tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers)
58 {
59         void    *stream = Buffer;
60          int    rem = Length;
61          int    op;
62         while( rem )
63         {
64                 rem --;
65                 op = *(Uint8*)stream;
66                 stream = (void*)((tVAddr)stream + 1);
67                 
68                 if(op > NUM_VIDEO_2DOPS) {
69                         Log_Warning("DrvUtil",
70                                 "DrvUtil_Video_2DStream: Unknown operation %i",
71                                 op);
72                         return Length-rem;
73                 }
74                 
75                 if(op*sizeof(void*) > SizeofHandlers) {
76                         Log_Warning("DrvUtil",
77                                 "DrvUtil_Video_2DStream: Driver does not support op %i",
78                                 op);
79                         return Length-rem;
80                 }
81                 
82                 switch(op)
83                 {
84                 case VIDEO_2DOP_NOP:    break;
85                 
86                 case VIDEO_2DOP_FILL:
87                         if(rem < 12)    return Length-rem;
88                         
89                         if(!Handlers->Fill) {
90                                 Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
91                                         " does not support VIDEO_2DOP_FILL");
92                                 return Length-rem;
93                         }
94                         
95                         Handlers->Fill(
96                                 Ent,
97                                 ((Uint16*)stream)[0], ((Uint16*)stream)[1],
98                                 ((Uint16*)stream)[2], ((Uint16*)stream)[3],
99                                 ((Uint32*)stream)[2]
100                                 );
101                         
102                         rem -= 12;
103                         stream = (void*)((tVAddr)stream + 12);
104                         break;
105                 
106                 case VIDEO_2DOP_BLIT:
107                         if(rem < 12)    return Length-rem;
108                         
109                         if(!Handlers->Blit) {
110                                 Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
111                                         " does not support VIDEO_2DOP_BLIT");
112                                 return Length-rem;
113                         }
114                         
115                         Handlers->Blit(
116                                 Ent,
117                                 ((Uint16*)stream)[0], ((Uint16*)stream)[1],
118                                 ((Uint16*)stream)[2], ((Uint16*)stream)[3],
119                                 ((Uint16*)stream)[4], ((Uint16*)stream)[5]
120                                 );
121                         
122                         rem -= 12;
123                         stream = (void*)((tVAddr)stream + 12);
124                         break;
125                 
126                 }
127         }
128         return 0;
129 }
130
131 int DrvUtil_Video_WriteLFB(tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, void *Buffer)
132 {
133         Uint8   *dest;
134          int    csr_x, csr_y;
135         ENTER("pFBInfo xOffset xLength pBuffer",
136                 Mode, FBInfo, Offset, Length, Buffer);
137
138         csr_x = FBInfo->CursorX;
139         csr_y = FBInfo->CursorY;
140
141         DrvUtil_Video_RemoveCursor(FBInfo);
142
143         switch( FBInfo->BufferFormat )
144         {
145         case VIDEO_BUFFMT_TEXT:
146                 {
147                 tVT_Char        *chars = Buffer;
148                  int    bytes_per_px = (FBInfo->Depth + 7) / 8;
149                  int    widthInChars = FBInfo->Width/giVT_CharWidth;
150                  int    heightInChars = FBInfo->Height/giVT_CharHeight;
151                  int    x, y, i;
152         
153                 LOG("bytes_per_px = %i", bytes_per_px);
154                 LOG("widthInChars = %i, heightInChars = %i", widthInChars, heightInChars);
155         
156                 Length /= sizeof(tVT_Char);     Offset /= sizeof(tVT_Char);
157                 
158                 x = Offset % widthInChars;      y = Offset / widthInChars;
159                 LOG("x = %i, y = %i", x, y);    
160         
161                 // Sanity Check
162                 if(Offset > heightInChars * widthInChars)       LEAVE_RET('i', 0);
163                 if(y >= heightInChars)  LEAVE_RET('i', 0);
164                 
165                 if( Offset + Length > heightInChars*widthInChars )
166                 {
167                         Length = heightInChars*widthInChars - Offset;
168                 }
169                 
170                 dest = FBInfo->Framebuffer;
171                 LOG("dest = %p", dest);
172                 dest += y * giVT_CharHeight * FBInfo->Pitch;
173                 LOG("dest = %p", dest);
174                 
175                 for( i = 0; i < Length; i++ )
176                 {
177                         if( y >= heightInChars )
178                         {
179                                 Log_Notice("DrvUtil", "Stopped at %i", i);
180                                 break;
181                         }
182
183                         VT_Font_Render(
184                                 chars->Ch,
185                                 dest + x*giVT_CharWidth*bytes_per_px, FBInfo->Depth, FBInfo->Pitch,
186                                 VT_Colour12toN(chars->BGCol, FBInfo->Depth),
187                                 VT_Colour12toN(chars->FGCol, FBInfo->Depth)
188                                 );
189                         
190                         chars ++;
191                         x ++;
192                         if( x >= widthInChars )
193                         {
194                                 x = 0;
195                                 y ++;
196                                 dest += FBInfo->Pitch*giVT_CharHeight;
197                                 LOG("dest = %p", dest);
198                         }
199                 }
200                 Length = i * sizeof(tVT_Char);
201                 }
202                 break;
203         
204         case VIDEO_BUFFMT_FRAMEBUFFER:
205                 if(FBInfo->Width*FBInfo->Height*4 < Offset+Length)
206                 {
207                         Log_Warning("DrvUtil", "DrvUtil_Video_WriteLFB - Framebuffer Overflow");
208                         return 0;
209                 }
210                 
211                 //TODO: Handle non 32-bpp framebuffer modes
212                 if( FBInfo->Depth != 32 ) {
213                         Log_Warning("DrvUtil", "DrvUtil_Video_WriteLFB - Don't support non 32-bpp FB mode");
214                         return 0;
215                 }       
216
217                 
218                 //TODO: Handle pitch != Width*BytesPerPixel
219                 // Copy to Frambuffer
220                 dest = (Uint8 *)FBInfo->Framebuffer + Offset;
221                 memcpy(dest, Buffer, Length);
222                 break;
223         
224         case VIDEO_BUFFMT_2DSTREAM:
225                 Length = DrvUtil_Video_2DStream(
226                         FBInfo, Buffer, Length,
227                         &gDrvUtil_Stub_2DFunctions, sizeof(gDrvUtil_Stub_2DFunctions)
228                         );
229                 break;
230         
231         default:
232                 LEAVE('i', -1);
233                 return -1;
234         }
235
236         DrvUtil_Video_DrawCursor(FBInfo, csr_x, csr_y);
237
238         LEAVE('x', Length);
239         return Length;
240 }
241
242 int DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap)
243 {
244          int    csrX = Buf->CursorX, csrY = Buf->CursorY;
245         size_t  size;
246
247         // Clear old bitmap
248         if( Buf->CursorBitmap )
249         {
250                 DrvUtil_Video_RemoveCursor(Buf);
251                 if( !Bitmap || Bitmap->W != Buf->CursorBitmap->W || Bitmap->H != Buf->CursorBitmap->H )
252                 {
253                         free( Buf->CursorSaveBuf );
254                         Buf->CursorSaveBuf = NULL;
255                 }
256                 if( Buf->CursorBitmap != &gDrvUtil_TextModeCursor)
257                         free(Buf->CursorBitmap);
258                 Buf->CursorBitmap = NULL;
259         }
260         
261         // If the new bitmap is null, disable drawing
262         if( !Bitmap )
263         {
264                 Buf->CursorX = -1;
265                 Buf->CursorY = -1;
266                 return 0;
267         }
268
269         // Sanity check the bitmap
270         if( !CheckMem(Bitmap, sizeof(*Bitmap)) || !CheckMem(Bitmap->Data, Bitmap->W*Bitmap->H*sizeof(Uint32)) )
271         {
272                 Log_Warning("DrvUtil", "DrvUtil_Video_SetCursor: Bitmap (%p) is in invalid memory", Bitmap);
273                 errno = -EINVAL;
274                 return -1;
275         }
276
277         // Don't take a copy of the DrvUtil provided cursor
278         if( Bitmap == &gDrvUtil_TextModeCursor )
279         {
280                 Buf->CursorBitmap = Bitmap;
281         }
282         else
283         {
284                 size = sizeof(tVideo_IOCtl_Bitmap) + Bitmap->W*Bitmap->H*4;
285                 
286                 // Take a copy
287                 Buf->CursorBitmap = malloc( size );
288                 memcpy(Buf->CursorBitmap, Bitmap, size);
289         }
290         
291         // Restore cursor position
292         DrvUtil_Video_DrawCursor(Buf, csrX, csrY);
293         return 0;
294 }
295
296 void DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y)
297 {
298          int    render_ox=0, render_oy=0, render_w, render_h;
299
300         DrvUtil_Video_RemoveCursor(Buf);
301
302         // X < 0 disables the cursor
303         if( X < 0 ) {
304                 Buf->CursorX = -1;
305                 return ;
306         }
307
308         // Sanity checking
309         if( X < 0 || Y < 0 )    return;
310         if( X >= Buf->Width || Y >= Buf->Height )       return;
311
312         // Ensure the cursor is enabled
313         if( !Buf->CursorBitmap )        return ;
314         
315         // Save cursor position (for changing the bitmap)
316         Buf->CursorX = X;       Buf->CursorY = Y;
317
318         // Apply cursor's center offset
319         X -= Buf->CursorBitmap->XOfs;
320         Y -= Buf->CursorBitmap->YOfs;
321         
322         // Get the width of the cursor on screen (clipping to right/bottom edges)
323         render_w = X > Buf->Width  - Buf->CursorBitmap->W ? Buf->Width  - X : Buf->CursorBitmap->W;
324         render_h = Y > Buf->Height - Buf->CursorBitmap->H ? Buf->Height - Y : Buf->CursorBitmap->H;
325
326         // Clipp to left/top edges
327         if(X < 0) {     render_ox = -X; X = 0;  }
328         if(Y < 0) {     render_oy = -Y; Y = 0;  }
329
330         // Save values
331         Buf->CursorRenderW = render_w;  Buf->CursorRenderH = render_h;
332         Buf->CursorDestX   = X;         Buf->CursorDestY = Y;
333         Buf->CursorReadX   = render_ox; Buf->CursorReadY = render_oy;
334
335         // Call render routine
336         DrvUtil_Video_RenderCursor(Buf);
337 }
338
339 void DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf)
340 {
341          int    src_x = Buf->CursorReadX, src_y = Buf->CursorReadY;
342          int    render_w = Buf->CursorRenderW, render_h = Buf->CursorRenderH;
343          int    dest_x = Buf->CursorDestX, dest_y = Buf->CursorDestY;
344          int    bytes_per_px = (Buf->Depth + 7) / 8;
345          int    save_pitch = Buf->CursorBitmap->W * bytes_per_px;
346         void    *dest;
347         Uint32  *src;
348          int    x, y;
349
350 //      Debug("DrvUtil_Video_RenderCursor: (Buf=%p) dest_x=%i, dest_y=%i", Buf, dest_x, dest_y);
351
352         dest = (Uint8*)Buf->Framebuffer + dest_y*Buf->Pitch + dest_x*bytes_per_px;
353         src = Buf->CursorBitmap->Data + src_y * Buf->CursorBitmap->W + src_x;
354         
355         // Allocate save buffer if not already
356         if( !Buf->CursorSaveBuf )
357                 Buf->CursorSaveBuf = malloc( Buf->CursorBitmap->W*Buf->CursorBitmap->H*bytes_per_px );
358
359         // Save behind the cursor
360         for( y = 0; y < render_h; y ++ )
361                 memcpy(
362                         (Uint8*)Buf->CursorSaveBuf + y*save_pitch,
363                         (Uint8*)dest + y*Buf->Pitch,
364                         render_w*bytes_per_px
365                         );
366         // Draw the cursor
367         switch(Buf->Depth)
368         {
369         case 32:
370                 for( y = 0; y < render_h; y ++ )
371                 {
372                         for(x = 0; x < render_w; x ++ )
373                         {
374                                 // TODO: Should I implement alpha blending?
375                                 if(src[x] & 0xFF000000)
376                                         ((Uint32*)dest)[x] = src[x];
377                                 else
378                                         ;       // NOP, completely transparent
379                         }
380                         src += Buf->CursorBitmap->W;
381                         dest = (Uint8*)dest + Buf->Pitch;
382                 }
383                 break;
384         default:
385                 Log_Error("DrvUtil", "TODO: Implement non 32-bpp cursor");
386                 break;
387         }
388 }
389
390 void DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf)
391 {
392          int    bytes_per_px = (Buf->Depth + 7) / 8;
393          int    y, save_pitch;
394         Uint8   *dest, *src;
395
396         // Just a little sanity
397         if( !Buf->CursorBitmap || Buf->CursorX == -1 )  return ;
398         if( !Buf->CursorSaveBuf )       return ;
399
400 //      Debug("DrvUtil_Video_RemoveCursor: (Buf=%p) dest_x=%i, dest_y=%i", Buf, Buf->CursorDestX, Buf->CursorDestY);
401
402         // Set up
403         save_pitch = Buf->CursorBitmap->W * bytes_per_px;
404         dest = (Uint8*)Buf->Framebuffer + Buf->CursorDestY * Buf->Pitch + Buf->CursorDestX*bytes_per_px;
405         src = Buf->CursorSaveBuf;
406         
407         // Copy each line back
408         for( y = 0; y < Buf->CursorRenderH; y ++ )
409         {
410                 memcpy( dest, src, Buf->CursorRenderW * bytes_per_px );
411                 src += save_pitch;
412                 dest += Buf->Pitch;
413         }
414         
415         // Set the cursor as removed
416         Buf->CursorX = -1;
417 }
418
419 void DrvUtil_Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour)
420 {
421         tDrvUtil_Video_BufInfo  *FBInfo = Ent;
422
423         // TODO: Handle non-32bit modes
424         if( FBInfo->Depth != 32 )       return;
425
426         // TODO: Be less hacky
427          int    pitch = FBInfo->Pitch/4;
428         Uint32  *buf = (Uint32*)FBInfo->Framebuffer + Y*pitch + X;
429         while( H -- ) {
430                 Uint32 *tmp;
431                  int    i;
432                 tmp = buf;
433                 for(i=W;i--;tmp++)      *tmp = Colour;
434                 buf += pitch;
435         }
436 }
437
438 void DrvUtil_Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H)
439 {
440         tDrvUtil_Video_BufInfo  *FBInfo = Ent;
441          int    scrnpitch = FBInfo->Pitch;
442          int    bytes_per_px = (FBInfo->Depth + 7) / 8;
443          int    dst = DstY*scrnpitch + DstX;
444          int    src = SrcY*scrnpitch + SrcX;
445          int    tmp;
446         
447         //Log("Vesa_2D_Blit: (Ent=%p, DstX=%i, DstY=%i, SrcX=%i, SrcY=%i, W=%i, H=%i)",
448         //      Ent, DstX, DstY, SrcX, SrcY, W, H);
449         
450         if(SrcX + W > FBInfo->Width)    W = FBInfo->Width - SrcX;
451         if(DstX + W > FBInfo->Width)    W = FBInfo->Width - DstX;
452         if(SrcY + H > FBInfo->Height)   H = FBInfo->Height - SrcY;
453         if(DstY + H > FBInfo->Height)   H = FBInfo->Height - DstY;
454         
455         //Debug("W = %i, H = %i", W, H);
456         
457         if( dst > src ) {
458                 // Reverse copy
459                 dst += H*scrnpitch;
460                 src += H*scrnpitch;
461                 while( H -- ) {
462                         dst -= scrnpitch;
463                         src -= scrnpitch;
464                         tmp = W*bytes_per_px;
465                         for( tmp = W; tmp --; ) {
466                                 *((Uint8*)FBInfo->Framebuffer + dst + tmp) = *((Uint8*)FBInfo->Framebuffer + src + tmp);
467                         }
468                 }
469         }
470         else {
471                 // Normal copy is OK
472                 while( H -- ) {
473                         memcpy((Uint8*)FBInfo->Framebuffer + dst, (Uint8*)FBInfo->Framebuffer + src, W*bytes_per_px);
474                         dst += scrnpitch;
475                         src += scrnpitch;
476                 }
477         }
478         //Log("Vesa_2D_Blit: RETURN");
479 }
480         
481
482 // --- Disk Driver Helpers ---
483 Uint64 DrvUtil_ReadBlock(Uint64 Start, Uint64 Length, void *Buffer,
484         tDrvUtil_Callback ReadBlocks, Uint64 BlockSize, Uint Argument)
485 {
486         Uint8   tmp[BlockSize]; // C99
487         Uint64  block = Start / BlockSize;
488          int    offset = Start - block * BlockSize;
489          int    leading = BlockSize - offset;
490         Uint64  num;
491          int    tailings;
492         Uint64  ret;
493         
494         ENTER("XStart XLength pBuffer pReadBlocks XBlockSize xArgument",
495                 Start, Length, Buffer, ReadBlocks, BlockSize, Argument);
496         
497         // Non aligned start, let's fix that!
498         if(offset != 0)
499         {
500                 if(leading > Length)    leading = Length;
501                 LOG("Reading %i bytes from Block1+%i", leading, offset);
502                 ret = ReadBlocks(block, 1, tmp, Argument);
503                 if(ret != 1) {
504                         LEAVE('i', 0);
505                         return 0;
506                 }
507                 memcpy( Buffer, &tmp[offset], leading );
508                 
509                 if(leading == Length) {
510                         LEAVE('i', leading);
511                         return leading;
512                 }
513                 
514                 Buffer = (Uint8*)Buffer + leading;
515                 block ++;
516                 num = ( Length - leading ) / BlockSize;
517                 tailings = Length - num * BlockSize - leading;
518         }
519         else {
520                 num = Length / BlockSize;
521                 tailings = Length % BlockSize;
522         }
523         
524         // Read central blocks
525         if(num)
526         {
527                 LOG("Reading %i blocks", num);
528                 ret = ReadBlocks(block, num, Buffer, Argument);
529                 if(ret != num ) {
530                         LEAVE('X', leading + ret * BlockSize);
531                         return leading + ret * BlockSize;
532                 }
533         }
534         
535         // Read last tailing block
536         if(tailings != 0)
537         {
538                 LOG("Reading %i bytes from last block", tailings);
539                 block += num;
540                 Buffer = (Uint8*)Buffer + num * BlockSize;
541                 ret = ReadBlocks(block, 1, tmp, Argument);
542                 if(ret != 1) {
543                         LEAVE('X', leading + num * BlockSize);
544                         return leading + num * BlockSize;
545                 }
546                 memcpy( Buffer, tmp, tailings );
547         }
548         
549         LEAVE('X', Length);
550         return Length;
551 }
552
553 Uint64 DrvUtil_WriteBlock(Uint64 Start, Uint64 Length, void *Buffer,
554         tDrvUtil_Callback ReadBlocks, tDrvUtil_Callback WriteBlocks,
555         Uint64 BlockSize, Uint Argument)
556 {
557         Uint8   tmp[BlockSize]; // C99
558         Uint64  block = Start / BlockSize;
559          int    offset = Start - block * BlockSize;
560          int    leading = BlockSize - offset;
561         Uint64  num;
562          int    tailings;
563         Uint64  ret;
564         
565         ENTER("XStart XLength pBuffer pReadBlocks pWriteBlocks XBlockSize xArgument",
566                 Start, Length, Buffer, ReadBlocks, WriteBlocks, BlockSize, Argument);
567         
568         // Non aligned start, let's fix that!
569         if(offset != 0)
570         {
571                 if(leading > Length)    leading = Length;
572                 LOG("Writing %i bytes to Block1+%i", leading, offset);
573                 // Read a copy of the block
574                 ret = ReadBlocks(block, 1, tmp, Argument);
575                 if(ret != 1) {
576                         LEAVE('i', 0);
577                         return 0;
578                 }
579                 // Modify
580                 memcpy( &tmp[offset], Buffer, leading );
581                 // Write Back
582                 ret = WriteBlocks(block, 1, tmp, Argument);
583                 if(ret != 1) {
584                         LEAVE('i', 0);
585                         return 0;
586                 }
587                 
588                 if(leading == Length) {
589                         LEAVE('i', leading);
590                         return leading;
591                 }
592                 
593                 Buffer = (Uint8*)Buffer + leading;
594                 block ++;
595                 num = ( Length - leading ) / BlockSize;
596                 tailings = Length - num * BlockSize - leading;
597         }
598         else {
599                 num = Length / BlockSize;
600                 tailings = Length % BlockSize;
601         }
602         
603         // Read central blocks
604         if(num)
605         {
606                 LOG("Writing %i blocks", num);
607                 ret = WriteBlocks(block, num, Buffer, Argument);
608                 if(ret != num ) {
609                         LEAVE('X', leading + ret * BlockSize);
610                         return leading + ret * BlockSize;
611                 }
612         }
613         
614         // Read last tailing block
615         if(tailings != 0)
616         {
617                 LOG("Writing %i bytes to last block", tailings);
618                 block += num;
619                 Buffer = (Uint8*)Buffer + num * BlockSize;
620                 // Read
621                 ret = ReadBlocks(block, 1, tmp, Argument);
622                 if(ret != 1) {
623                         LEAVE('X', leading + num * BlockSize);
624                         return leading + num * BlockSize;
625                 }
626                 // Modify
627                 memcpy( tmp, Buffer, tailings );
628                 // Write
629                 ret = WriteBlocks(block, 1, tmp, Argument);
630                 if(ret != 1) {
631                         LEAVE('X', leading + num * BlockSize);
632                         return leading + num * BlockSize;
633                 }
634                 
635         }
636         
637         LEAVE('X', Length);
638         return Length;
639 }

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