1 #include "asmsupport.h"
5 #include <exec/types.h>
6 #include <exec/lists.h>
8 #include <proto/exec.h>
13 #include "blockstructure.h"
19 void ClearMemQuick(void *mem
, LONG bytes
) {
30 #ifdef WORDCOMPRESSION
32 void uncompress(UWORD
*dest
,UBYTE
*data
,UWORD length
) {
34 UBYTE
*end
=data
+length
;
37 /* Decompresses a transaction into /dest/ using /data/ which is
38 /length/ bytes long. */
43 if((code
& 0xC0)==0x40) {
45 dest
+=(code
& 0x3F)+1;
47 else if((code
& 0xC0)==0x80) { // else if((code & 0xE0)==0x20) {
49 len
=(code
& 0x3F)+1; // len=(code & 0x1F)+1;
55 else if((code
& 0xC0)==0x00) { // else if((code & 0xE0)==0x00) {
57 len
=(code
& 0x3F)+1; // len=(code & 0x1F)+1;
78 WORD
compress(UWORD
*org
,UWORD
*new,UBYTE
*dest
) {
79 WORD unchanged
,cleared
,set
,immediate
;
83 UWORD
*end
=new+(bytes_block
>>1);
99 while(*o
++==*n
++ && ++unchanged
<max
) {
105 while(*n
++==0 && ++cleared
<max
) {
110 while(*n
++==0xFFFF && ++set
<max
) {
114 /* Largest of unchanged, cleared and set wins! */
116 if(unchanged
!=0 || cleared
!=set
) {
119 if(unchanged
>=cleared
&& unchanged
>=set
) {
120 *dest
++=0x40+unchanged
-1;
123 else if(cleared
!=0) {
128 *dest
++=0x80+set
-1; // *dest++=0x20+set-1;
136 /* Data wasn't unchanged, cleared or set */
143 while(*n
!=0 && *n
!=0xFFFF && *o
++!=*n
++ && ++immediate
<max
) {
148 *dest
++=0xC0+immediate
-1;
149 o
=(UWORD
*)dest
; /* 68020 only! */
150 while(immediate
-->0) {
157 return((WORD
)(dest
-begin
));
162 WORD
compressfromzero(UWORD
*new,UBYTE
*dest
) {
163 WORD cleared
,set
,immediate
;
166 UWORD
*end
=new+(bytes_block
>>1);
180 while(*n
++==0 && ++cleared
<max
) {
185 while(*n
++==0xFFFF && ++set
<max
) {
188 /* Largest of cleared and set wins! */
198 *dest
++=0x80+set
-1; // *dest++=0x20+set-1;
205 /* Data wasn't cleared or set */
211 while(*n
!=0 && *n
++!=0xFFFF && ++immediate
<max
) {
214 *dest
++=0xC0+immediate
-1;
215 n
=(UWORD
*)dest
; /* 68020 only! */
216 while(immediate
-->0) {
223 return((WORD
)(dest
-begin
));
229 #ifdef LONGCOMPRESSION
231 void uncompress(ULONG
*dest
,UBYTE
*data
,UWORD length
) {
233 UBYTE
*end
=data
+length
;
236 /* Decompresses a transaction into /dest/ using /data/ which is
237 /length/ bytes long. */
242 if((code
& 0xC0)==0x40) {
244 dest
+=(code
& 0x3F)+1;
246 else if((code
& 0xC0)==0x80) { // else if((code & 0xE0)==0x20) {
248 len
=(code
& 0x3F)+1; // len=(code & 0x1F)+1;
254 else if((code
& 0xC0)==0x00) { // else if((code & 0xE0)==0x00) {
256 len
=(code
& 0x3F)+1; // len=(code & 0x1F)+1;
277 WORD
compress(ULONG
*org
,ULONG
*new,UBYTE
*dest
) {
278 WORD unchanged
,cleared
,set
,immediate
;
282 ULONG
*end
=new+(globals
->bytes_block
>>2);
298 while(*o
++==*n
++ && ++unchanged
<max
) {
304 while(*n
++==0 && ++cleared
<max
) {
309 while(*n
++==0xFFFFFFFF && ++set
<max
) {
313 /* Largest of unchanged, cleared and set wins! */
315 if(unchanged
!=0 || cleared
!=set
) {
318 if(unchanged
>=cleared
&& unchanged
>=set
) {
319 *dest
++=0x40+unchanged
-1;
322 else if(cleared
!=0) {
327 *dest
++=0x80+set
-1; // *dest++=0x20+set-1;
335 /* Data wasn't unchanged, cleared or set */
342 while(*n
!=0 && *n
!=0xFFFFFFFF && *o
++!=*n
++ && ++immediate
<max
) {
347 *dest
++=0xC0+immediate
-1;
348 o
=(ULONG
*)dest
; /* 68020 only! */
349 while(immediate
-->0) {
356 return((WORD
)(dest
-begin
));
361 WORD
compressfromzero(ULONG
*new,UBYTE
*dest
) {
362 WORD cleared
,set
,immediate
;
365 ULONG
*end
=new+(globals
->bytes_block
>>2);
379 while(*n
++==0 && ++cleared
<max
) {
384 while(*n
++==0xFFFFFFFF && ++set
<max
) {
387 /* Largest of cleared and set wins! */
397 *dest
++=0x80+set
-1; // *dest++=0x20+set-1;
404 /* Data wasn't cleared or set */
410 while(*n
!=0 && *n
++!=0xFFFFFFFF && ++immediate
<max
) {
413 *dest
++=0xC0+immediate
-1;
414 n
=(ULONG
*)dest
; /* 68020 only! */
415 while(immediate
-->0) {
422 return((WORD
)(dest
-begin
));
431 void uncompress(ULONG
*dest
,UBYTE
*data
,UWORD length
) {
432 CopyMem(data
,dest
,length
);
438 WORD
compress(ULONG
*org
,ULONG
*new,UBYTE
*dest
) {
439 CopyMem(new,dest
,bytes_block
);
441 return((WORD
)bytes_block
);
446 WORD
compressfromzero(ULONG
*new,UBYTE
*dest
) {
447 CopyMem(new,dest
,bytes_block
);
449 return((WORD
)bytes_block
);
455 #ifdef ALTERNATIVECOMPRESSION
457 void uncompress(ULONG
*dest
, UBYTE
*data
, UWORD length
) {
461 UBYTE
*dataend
=data
+length
;
475 while(data
<dataend
) {
491 UWORD
compress(ULONG
*org
, ULONG
*new, UBYTE
*dest
) {
493 UWORD longs_block
=bytes_block
>>2;
494 UWORD longsleft
=longs_block
;
496 UBYTE
*deststart
=dest
;
505 return((UWORD
)(dest
-deststart
));
509 *dest
++=longs_block
-longsleft
;
510 destl
=(ULONG
*)(dest
+1);
520 return((UWORD
)(dest
-deststart
));
531 UWORD
compressfromzero(ULONG
*new, UBYTE
*dest
) {
533 UWORD longs_block
=bytes_block
>>2;
534 UWORD longsleft
=longs_block
;
536 UBYTE
*deststart
=dest
;
544 return((UWORD
)(dest
-deststart
));
548 *dest
++=longs_block
-longsleft
;
549 destl
=(ULONG
*)(dest
+1);
558 return((UWORD
)(dest
-deststart
));
571 UBYTE
*stripcolon(UBYTE
*path
) {
574 /* Finds the last colon in the path string (if any) and returns a pointer
575 to the character following it. If no colon is found you get a pointer
576 to the first character in the string. */
589 UBYTE
upperchar(UBYTE c
) {
590 if((c
>=224 && c
<=254 && c
!=247) || (c
>='a' && c
<='z')) {
598 UWORD
hash(UBYTE
*name
, WORD casesensitive
) {
601 /* Calculates a hash value over the passed in string. The end of the string
602 can be either a NUL byte or a slash. The hash function is the same as the
603 one used in FastFileSystem set to international mode. */
605 while(name
[hash
]!=0 && name
[hash
]!='/') {
609 if(casesensitive
==FALSE
) {
610 while(*name
!=0 && *name
!='/') {
611 hash
=hash
*13+upperchar(*name
++);
615 while(*name
!=0 && *name
!='/') {
616 hash
=hash
*13+*name
++;
624 UBYTE
*validatepath(UBYTE
*string
) {
630 /* This functions limits the length of any path-part of the passed in string
631 to max_name_length characters. It also strips the colons. */
633 string
=stripcolon(string
);
638 cnt
=globals
->max_name_length
;
640 while((c
=*string
++)!=0) {
642 cnt
=globals
->max_name_length
+1;
656 BYTE
isvalidcomponentname(UBYTE
*name
) {
659 /* This function returns FALSE if the passed name
660 is empty or contains a slash or colon. */
662 if(name
==0 || *name
==0) {
666 while((c
=*name
++)!=0) {
667 if(c
==':' || c
=='/') {
676 void copystr(UBYTE
*src
,UBYTE
*dest
,WORD maxlen
) {
678 /* maxlen is the maximum stringlength the destination can become, excluding zero
681 while(--maxlen
>=0 && (*dest
++=*src
++)!=0) {
693 UWORD
copybstrasstr(BSTR bstr
,UBYTE
*str
,UWORD maxlen
)
695 UBYTE
*srcstr
= BADDR(bstr
);
698 /* maxlen is the maximum stringlength the destination can become, excluding zero
699 termination. The return value is the length of the destination string also
700 excluding termination. */
702 srclen
= strlen(srcstr
);
718 UWORD
bstrlen(UBYTE
*str
) {
722 if(len
!=0 && str
[len
]==0) {
728 UWORD
copybstrasstr(BSTR bstr
,UBYTE
*str
,UWORD maxlen
) {
729 UBYTE
*srcstr
=BADDR(bstr
);
730 UWORD srclen
=bstrlen(srcstr
);
732 /* maxlen is the maximum stringlength the destination can become, excluding zero
733 termination. The return value is the length of the destination string also
734 excluding termination. */
753 void initlist(struct List
*list
) {
754 list
->lh_Head
=(struct Node
*)&list
->lh_Tail
;
756 list
->lh_TailPred
=(struct Node
*)list
;
762 ULONG
datestamptodate(struct DateStamp
*datestamp
) {
763 return( (ULONG
)((UWORD
)datestamp
->ds_Tick
/50) + (ULONG
)((UWORD
)datestamp
->ds_Minute
*60) + datestamp
->ds_Days
*86400 );
768 void datetodatestamp(ULONG date
,struct DateStamp
*datestamp
) {
771 datestamp
->ds_Days
= date
/86400;
773 seconds
=date
- (datestamp
->ds_Days
* 86400);
775 datestamp
->ds_Minute
= (ULONG
)((UWORD
)(seconds
/60));
776 datestamp
->ds_Tick
= (ULONG
)((UWORD
)(seconds
%60)*50);
781 ULONG
getdate(void) {
782 struct DateStamp datestamp
;
784 DateStamp(&datestamp
);
786 return( datestamptodate(&datestamp
) );
792 void mergediffs(ULONG
*current
, UBYTE
*olddiff
, UWORD length
, UBYTE
*newdiff
, UWORD
*offsets
) {
796 *newdiff
++=*olddiff
++;
798 bytestoskip
=*offset
& 0x0003;
799 longoffset
=(*offsets
++)>>2;
801 if(longoffset
<*olddiff
) {
802 c
=current
+longoffset
;
804 *newdiff
++=longoffset
;
805 newdiffl
=(ULONG
*)(newdiff
+1);
816 newdiff
=(UBYTE
*)newdiffl
;
823 void mergediffs(UBYTE
*diff
, UWORD length
, UBYTE
*dest
, UWORD offsets
[], UBYTE lengths
[], UBYTE data
[]) {
827 byteoffset
=offsets
[n
];
832 if((unitsdone
+len
)<<2 > byteoffset
) {
834 /* Current code contains part of data which needs to be modified. */
836 if((code
& 0x40)==0) { /* Clear or Set */
849 void adddiff(UBYTE
*previouscode
, UBYTE newcode
, ) {
855 void mergediffs(UBYTE
*diff
, UWORD length
, UBYTE
*newdiff
, UWORD newlength
, UBYTE
*dest
) {
856 UWORD newunitsdone
=0; /* Words/Longs already merged. */
861 /* Merges two diffs into a single diff. */
863 /* 0x00 -> clear, 0x40 -> unchanged, 0x80 -> set, 0xC0 -> copy */
869 if((code
& 0x40)==0) { /* Clear or Set */
873 else if((code
& 0x80)!=0) { /* Copy */
881 newdiffl
=(ULONG
*)newdiff
;
884 *destl
++=*newdiffl
++;
888 newdiff
=(UBYTE
*)newdiffl
;
890 else { /* Unchanged */
892 /* In this case the new diff contains a block of unchanged data.
893 This means we need to check the old diff to see what needs to
897 len2
=(code2
& 0x3F)+1;
899 if(unitsdone
+len2
> newunitsdone
) {
902 /* Current code in old diff is overlapping the unchanged area. */
904 offset
=newunitsdone
-unitsdone
;
905 size
=unitsdone
+len2
- newunitsdone
;
906 if(size
>len
) { /* Check if overlapping area is smaller */
910 /* Calculated size and offset of overlapping area. */
915 if((code2
& 0xC0)==0xC0) { /* Copy */
916 /* Skips any data for copy. */
943 Operations are currently a diff of the original
and the
new
944 block
. Creating
this diff takes a lot of time
and can
945 reduce performance considerably
.
947 It should be possible to merge
2 diffs quickly without
948 having to creating an entirely
new diff
. This can be
949 accomplished by creating a function which takes
2 diffs
and
950 merges them into one
, letting the newer diff take
953 Another function which would be needed is a function which
954 can create a diff based on the information to be changed
955 only
. Old code which changes just a single piece of
956 information in a CacheBuffer looks like
this:
959 preparecachebuffer(cb
);
961 o
->object
.file
.size
=x
;
963 errorcode
=storecachebuffer(cb
);
966 Instead it could be much faster
if written like
this:
969 changecachebuffer(cb
, &o
->object
.file
.size
, x
);
987 1 byte offset, 1 byte length. In LONGS.
991 void uncompress(ULONG
*dest
, UBYTE
*data
, UWORD length
) {
995 UBYTE
*dataend
=data
+length
;
1009 while(data
<dataend
) {
1013 datal
=(ULONG
*)data
;
1019 data
=(UBYTE
*)datal
;
1025 UWORD
compress(ULONG
*org
, ULONG
*new, UBYTE
*dest
) {
1027 UWORD longs_block
=bytes_block
>>2;
1028 UWORD longsleft
=longs_block
;
1030 UBYTE
*deststart
=dest
;
1038 if(--longsleft
==0) {
1039 return(dest
-deststart
);
1043 *dest
++=longs_block
-longsleft
;
1044 destl
=(ULONG
*)(dest
+2);
1051 if(--longsleft
==0) {
1053 dest
=(UBYTE
*)destl
;
1054 return(dest
-deststart
);
1056 } while(*org
!=*new);
1059 dest
=(UBYTE
*)destl
;
1065 UWORD
compressfromzero(ULONG
*new, UBYTE
*dest
) {
1067 UWORD longs_block
=bytes_block
>>2;
1068 UWORD longsleft
=longs_block
;
1070 UBYTE
*deststart
=dest
;
1077 if(--longsleft
==0) {
1078 return(dest
-deststart
);
1082 *dest
++=longs_block
-longsleft
;
1083 destl
=(ULONG
*)(dest
+2);
1089 if(--longsleft
==0) {
1091 dest
=(UBYTE
*)destl
;
1092 return(dest
-deststart
);
1097 dest
=(UBYTE
*)destl
;
1107 #ifdef BLOCKCOMPRESSION
1112 Diff compression scheme.
1114 Depending on the block size there will be a special
1115 header block which contains 2 bits for every 32 bytes
1116 the block consists of. We'll assume blocks of 512
1120 UWORD
makediff(ULONG
*new, ULONG
*org
, ULONG
**io_diff
) {
1121 ULONG
*diff
=*io_diff
;
1126 for(n
=0; n
<8; n
++) {
1133 else if(data
==0xFFFFFFFF) {
1136 else if(data
!=*org
) {
1151 UWORD
makedifffromzero(ULONG
*new, ULONG
**io_diff
) {
1152 ULONG
*diff
=*io_diff
;
1157 for(n
=0; n
<8; n
++) {
1164 else if(data
==0xFFFFFFFF) {
1180 if(newfilesize
!=gh
->size
) {
1181 struct CacheBuffer
*cb
;
1184 if((errorcode
=readobject(lock
->objectnode
,&cb
,&o
))==0) {
1185 UBYTE modifiedblocks
[4]={0,0,0,255};
1187 preparecachebuffer(cb
);
1189 checksum_writelong(cb
->data
, &o
->object
.file
.size
, newfilesize
);
1191 gh
->size
=newfilesize
;
1193 modifiedblocks
[1]=(&o
->object
.file
.size
- cb
->data
)>>5;
1194 modifiedblocks
[2]=(&o
->object
.file
.size
- cb
->data
+3)>>5;
1196 errorcode
=changecachebuffer(cb
, modifiedblocks
)
1200 void checksum_writelong(struct fsBlockHeader
*bh
, void *dest
, ULONG data
) {
1202 /* Only handles longs written to even addresses! */
1203 original
=*((ULONG
*)dest
);
1204 *((ULONG
*)dest
)=data
;
1206 if(( ((UBYTE
*)bh
- (UBYTE
*)dest
) & 0x03)!=0) {
1207 /* Word aligned address. */
1209 original
=(original
<<16)|(original
>>16);
1210 data
=(data
<<16)|(data
>>16);
1212 bh
->checksum
=~(~bh
->checksum
- original
+ data
);
1220 UWORD
mergediffs(UBYTE
*olddiff
, UBYTE
*newdiff
, UWORD length
, ULONG
*new, ULONG
*org
, UBYTE
*modifiedblocks
) {
1221 ULONG
*header
=(ULONG
*)newdiff
;
1223 UWORD
*modesstart
=(UWORD
*)(newdiff
+bytes_block
+(bytes_block
>>4));
1224 UWORD
*modes
=(UWORD
*)(newdiff
+bytes_block
+(bytes_block
>>4));
1225 UWORD
*oldmodes
=(UWORD
*)(olddiff
+length
);
1229 mc
=*((ULONG
*)olddiff
);
1232 for(b
=0; b
<16; b
++) {
1235 if(b
==*modifiedblocks
) {
1238 while(*++modifiedblocks
==b
) {
1242 mode
=makedifffromzero(new, (ULONG
**)&newdiff
);
1245 mode
=makediff(new, org
, (ULONG
**)&newdiff
);
1248 if(mode
==0x5555) { // All copied.
1251 else if(mode
==0xAAAA) { // All cleared.
1260 switch(mc
& 0xC0000000) {
1263 ULONG
*newdiffl
=(ULONG
*)newdiff
;
1264 ULONG
*olddiffl
=(ULONG
*)olddiff
;
1270 *newdiffl
++=*olddiffl
++;
1273 newdiff
=(UBYTE
*)newdiffl
;
1274 olddiff
=(UBYTE
*)olddiffl
;
1282 ULONG
*newdiffl
=(ULONG
*)newdiff
;
1283 ULONG
*olddiffl
=(ULONG
*)olddiff
;
1293 if((mode
& 0xC000)==0x4000) {
1294 *newdiffl
++=*olddiffl
++;
1299 newdiff
=(UBYTE
*)newdiffl
;
1300 olddiff
=(UBYTE
*)olddiffl
;
1311 newdiffw
=(UWORD
*)newdiff
;
1313 while(modes
!=modesstart
) {
1314 *newdiffw
++=*modes
++;
1317 return((UWORD
)((UBYTE
*)newdiffw
-(UBYTE
*)header
));
1321 void uncompress(ULONG
*dest
, UBYTE
*diff
, UWORD length
) {
1323 UWORD
*modes
=(UWORD
*)(diff
+length
);
1326 mc
=*((ULONG
*)diff
);
1330 switch(mc
& 0xC0000000) {
1336 ULONG
*diffl
=(ULONG
*)diff
;
1343 diff
=(UBYTE
*)diffl
;
1357 ULONG
*diffl
=(ULONG
*)diff
;
1358 UWORD mode
=*--modes
;
1362 switch(mode
& 0xC000) {
1379 diff
=(UBYTE
*)diffl
;
1389 /* Blocks will be processed 32 bytes at the time.
1391 Master Control block:
1393 %00 = unchanged, no control word.
1394 %01 = 32 bytes of data, no control word.
1395 %10 = cleared (compress from zero!).
1396 %11 = use control word.
1400 %00 = unchanged (0x0000)
1401 %01 = use 32-bit value (0x5555)
1402 %10 = cleared (0xAAAA)
1403 %11 = set (0xFFFF) */
1407 UWORD
compress(ULONG
*new, ULONG
*org
, UBYTE
*diff
) {
1408 ULONG
*header
=(ULONG
*)diff
;
1410 UWORD
*modesstart
=(UWORD
*)(diff
+bytes_block
+(bytes_block
>>4));
1411 UWORD
*modes
=(UWORD
*)(diff
+bytes_block
+(bytes_block
>>4));
1421 mode
=makediff(new, org
, (ULONG
**)&diff
);
1426 else if(mode
==0xAAAA) {
1440 diffw
=(UWORD
*)diff
;
1442 while(modes
!=modesstart
) {
1446 return((UWORD
)((UBYTE
*)diffw
-(UBYTE
*)header
));
1451 UWORD
compressfromzero(ULONG
*new, UBYTE
*diff
) {
1452 ULONG
*header
=(ULONG
*)diff
;
1454 UWORD
*modesstart
=(UWORD
*)(diff
+bytes_block
+(bytes_block
>>4));
1455 UWORD
*modes
=(UWORD
*)(diff
+bytes_block
+(bytes_block
>>4));
1465 mode
=makedifffromzero(new, (ULONG
**)&diff
);
1470 else if(mode
==0xAAAA) {
1483 diffw
=(UWORD
*)diff
;
1485 while(modes
!=modesstart
) {
1489 return((UWORD
)((UBYTE
*)diffw
-(UBYTE
*)header
));
1499 void checksum_writelong_be(struct fsBlockHeader
*bh
, void *dest
, ULONG data
) {
1502 /* Only handles longs written to even addresses! */
1504 original
=BE2L(*((ULONG
*)dest
));
1505 *((ULONG
*)dest
)=L2BE(data
);
1507 if(( ((UBYTE
*)bh
- (UBYTE
*)dest
) & 0x03)!=0) {
1509 /* Word aligned address. */
1511 original
=(original
<<16)|(original
>>16);
1512 data
=(data
<<16)|(data
>>16);
1515 bh
->be_checksum
=~L2BE((~BE2L(bh
->be_checksum
) - original
+ data
));
1518 void checksum_writelong(struct fsBlockHeader
*bh
, void *dest
, ULONG data
) {
1522 /* Only handles longs written to even addresses! */
1524 original
=*((ULONG
*)dest
);
1525 *((ULONG
*)dest
)=data
;
1527 if(( ((UBYTE
*)bh
- (UBYTE
*)dest
) & 0x03)!=0) {
1529 /* Word aligned address. */
1531 original
=(original
<<16)|(original
>>16);
1532 data
=(data
<<16)|(data
>>16);
1535 bh
->be_checksum
=~(~bh
->be_checksum
- original
+ data
);
1537 checksum_writelong_be(bh
, dest
, data
);