?login_element?

Subversion Repositories NedoOS

Rev

Rev 420 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. // this is not a code to be separately compiled!
  2. // instead, it is included in mhmt-depack.c several times and depends on existing at include moment #define's to generate some compiling code
  3. //
  4. //                   // example defines:
  5. //#define DPK_CHECK  // check input stream for consistency
  6. //#define DPK_DEPACK // do depacking
  7. //#define DPK_REPERR // report errors via printf
  8. {
  9.         LONG i;
  10.  
  11.         ULONG check;
  12.         ULONG byte,bits;//,bitlen;
  13.  
  14.         LONG   disp=0;
  15.         LONG length=0; // if -3 - insertion match, if 0 - nothing to do
  16.  
  17.         ULONG skipdisp,skiplen;
  18.  
  19.         ULONG disptype;
  20. // fetch byte and add to existing disp
  21. #define DISP_PLUSBYTE 0
  22. // fetch 5 bits to disp
  23. #define DISP_ABCDE    1
  24. // common disp for 3+ lengthes
  25. #define DISP_COMMON   2
  26.  
  27.         ULONG docopy; // do copy from input instead of repeating
  28.  
  29.         ULONG expbitlen = 2; // expandable displacement
  30.  
  31.  
  32.         ULONG stop;
  33.  
  34.  
  35.         ULONG success = 1;
  36.  
  37.  
  38.  
  39.  
  40.  
  41.         // rewind input stream
  42.         //
  43.         check = depack_getbyte(DEPACK_GETBYTE_REWIND);
  44. #ifdef DPK_CHECK
  45.         if( 0xFFFFFFFF == check )
  46.         {
  47.  #ifdef DPK_REPERR
  48.                 printf("mhmt-depack-hrust.c:{} - Can't rewind input stream!\n");
  49.  #endif
  50.                 return 0;
  51.         }
  52. #endif
  53.  
  54.  
  55.         // manage zx header if needed
  56.         if( wrk.zxheader )
  57.         {
  58.                 // check for "HR" in beginning
  59.                 check = depack_getbyte(DEPACK_GETBYTE_NEXT);
  60. #ifdef DPK_CHECK
  61.                 if( 0xFFFFFFFF == check ) goto NO_BYTE_HST;
  62.                 if( check != 'H' )
  63.                 {
  64.  #ifdef DPK_REPERR
  65.                         printf("mhmt-depack-hrust.c:{} - Bad zx-header!\n");
  66.  #endif
  67.                         return 0;
  68.                 }
  69. #endif
  70.                 check = depack_getbyte(DEPACK_GETBYTE_NEXT);
  71. #ifdef DPK_CHECK
  72.                 if( 0xFFFFFFFF == check ) goto NO_BYTE_HST;
  73.                 if( check != 'R' )
  74.                 {
  75.  #ifdef DPK_REPERR
  76.                         printf("mhmt-depack-hrust.c:{} - Bad zx-header!\n");
  77.  #endif
  78.                         return 0;
  79.                 }
  80. #endif
  81.  
  82.                 // skip 10 bytes
  83.                 for(i=0;i<10;i++)
  84.                 {
  85.                         check = depack_getbyte(DEPACK_GETBYTE_NEXT);
  86. #ifdef DPK_CHECK
  87.                         if( 0xFFFFFFFF == check ) goto NO_BYTE_HST;
  88. #endif
  89.                 }
  90.         }
  91.  
  92.  
  93.  
  94.         // initialize bitstream first
  95.         //
  96.         check = depack_getbits(16,DEPACK_GETBITS_FORCE); // number 16 is ignored! - just for convenience here...
  97. #ifdef DPK_CHECK
  98.         if( 0xFFFFFFFF == check )
  99.         {
  100. NO_BITS_HST:
  101.  #ifdef DPK_REPERR
  102.                 printf("mhmt-depack-hrust.c:{} - Can't get bits from input stream!\n");
  103.  #endif
  104.                 return 0;
  105.         }
  106. #endif
  107.  
  108.  
  109.  
  110.         // then byte of input stream goes to the output unchanged
  111.         //
  112.         byte = depack_getbyte(DEPACK_GETBYTE_NEXT);
  113. #ifdef DPK_CHECK
  114.         if( 0xFFFFFFFF == byte )
  115.         {
  116. NO_BYTE_HST:
  117.  #ifdef DPK_REPERR
  118.                 printf("mhmt-depack-hrust.c:{} - Can't get byte from input stream!\n");
  119.  #endif
  120.                 return 0;
  121.         }
  122. #endif
  123.  
  124. #ifdef DPK_DEPACK
  125.         success = success && depack_outbyte( (UBYTE)(0x00FF&byte), DEPACK_OUTBYTE_ADD );
  126. #endif
  127.  
  128.  
  129.  
  130.         // now normal depacking loop
  131.         //
  132.         stop = 0;
  133.         while( (!stop) && success )
  134.         {
  135.                 skiplen  = 0;
  136.                 skipdisp = 0;
  137.                 disptype = DISP_PLUSBYTE;
  138.                 docopy = 0;
  139.  
  140.                 bits = depack_getbits(1,DEPACK_GETBITS_NEXT);
  141. #ifdef DPK_CHECK
  142.                 if( 0xFFFFFFFF == bits )
  143.                 {
  144.                         #ifdef DBG
  145.                         printf("line %d\n",__LINE__);
  146.                         #endif
  147.                         goto NO_BITS_HST;
  148.                 }
  149. #endif
  150.  
  151.                 if( 1&bits ) // %1<byte>
  152.                 {
  153.                         docopy = 1;
  154.                         length = 1;
  155.                 }
  156.                 else // %0xx
  157.                 {
  158.                         bits = depack_getbits(2,DEPACK_GETBITS_NEXT);
  159. #ifdef DPK_CHECK
  160.                         if( 0xFFFFFFFF == bits )
  161.                         {
  162.                                 #ifdef DBG
  163.                                 printf("line %d\n",__LINE__);
  164.                                 #endif
  165.                                 goto NO_BITS_HST;
  166.                         }
  167. #endif
  168.  
  169.                         switch( bits&3 )
  170.                         {
  171.                         case 0: // %000xxx
  172.  
  173.                                 bits = depack_getbits(3,DEPACK_GETBITS_NEXT);
  174. #ifdef DPK_CHECK
  175.                                 if( 0xFFFFFFFF == bits )
  176.                                 {
  177.                                         #ifdef DBG
  178.                                         printf("line %d\n",__LINE__);
  179.                                         #endif
  180.                                         goto NO_BITS_HST;
  181.                                 }
  182. #endif
  183.  
  184.                                 disp = (-8) | (bits&0x07); // FFFFFFF8..FFFFFFFF (-8..-1)
  185.                                 length = 1;
  186.  
  187.                                 skiplen  = 1;
  188.                                 skipdisp = 1;
  189.  
  190.                                 break;
  191.  
  192.  
  193.  
  194.  
  195.  
  196.  
  197.                         case 1: // %001 - 2 bytes or insertion match part 1
  198.  
  199.                                 length = 2;
  200.                                 skiplen = 1;
  201.  
  202.                                 bits = depack_getbits(2,DEPACK_GETBITS_NEXT);
  203. #ifdef DPK_CHECK
  204.                                         if( 0xFFFFFFFF == bits )
  205.                                         {
  206.                                                 #ifdef DBG
  207.                                                 printf("line %d\n",__LINE__);
  208.                                                 #endif
  209.                                                 goto NO_BITS_HST;
  210.                                         }
  211. #endif
  212.  
  213.                                 switch( bits&3 )
  214.                                 {
  215.                                 case 0: // %001 00 - disp FDxx
  216.                                         //disptype = DISP_PLUSBYTE; // default value
  217.                                         disp = (-768);
  218.  
  219.                                         break;
  220.  
  221.                                 case 1: // %001 01 - disp FExx
  222.                                         //disptype = DISP_PLUSBYTE; // default value
  223.                                         disp = (-512);
  224.  
  225.                                         break;
  226.  
  227.                                 case 2: // %001 10 - ff00..ffdf or insertion match
  228.  
  229.                                         byte = depack_getbyte(DEPACK_GETBYTE_NEXT);
  230. #ifdef DPK_CHECK
  231.                                         if( 0xFFFFFFFF == byte ) goto NO_BYTE_HST;
  232. #endif
  233.                                         skipdisp = 1;
  234.  
  235.                                         if( byte<0x00E0 ) // ff00..ffdf
  236.                                         {
  237.                                                 disp = (-256) | (byte&0x00FF);
  238.                                         }
  239.                                         else if( byte==0x00FE ) // expand bitlen of expandable displacement
  240.                                         {
  241.                                                 #ifdef DBG
  242.                                                         printf("expansion\n");
  243.                                                 #endif
  244.  
  245.                                                 length = 0; // nothing to do
  246.                                                 expbitlen++;
  247. //#ifdef DPK_CHECK
  248. //                                              if( expbitlen>8 )
  249. //                                              {
  250. // #ifdef DPK_REPERR
  251. //                                                      printf("mhmt-depack-hrust.c:{} - bitlen of expandable displacement expanded more than 16 bits!\n");
  252. // #endif
  253. //                                                      return 0;
  254. //                                              }
  255. //#endif
  256.                                                 // this is the fix to mimic Z80 depacker (what seems to be perfectly correct!)
  257.                                                 if( expbitlen > 8 )
  258.                                                         expbitlen = 1;
  259.                                         }
  260.                                         else // insertion match - xor 2
  261.                                         {
  262.                                                 length = (-3); // mark insertion match
  263.  
  264.                                                 byte = ((byte<<1)&0x00FE) | ((byte>>7)&0x01); // byte<<<1
  265.                                                 byte ^= 0x02;
  266.                                                 byte -= 15;
  267.  
  268.                                                 disp = (-256) | (byte&0x00FF);
  269.                                         }
  270.                                         break;
  271.  
  272.                                 case 3: // %001 11 - disp FFE0+[abcde]
  273.  
  274.                                         disptype = DISP_ABCDE;
  275.  
  276.                                         break;
  277.                                 }
  278.  
  279.                                 break;
  280.  
  281.  
  282.  
  283.                         case 2: // %010 - 3 bytes or something
  284.  
  285.                                 length = 3;
  286.                                 skiplen = 1;
  287.                                 disptype = DISP_COMMON;
  288.  
  289.                                 break;
  290.  
  291.  
  292.                         case 3: // %011 - varlen
  293.  
  294.                                 disptype = DISP_COMMON;
  295.  
  296.                                 break;
  297.                         }
  298.                 }
  299.  
  300.                         if( (!stop) && (!skiplen) && (!docopy) )
  301.                         {
  302.                                 // read variable length
  303.                                 bits = depack_getbits(2,DEPACK_GETBITS_NEXT);
  304. #ifdef DPK_CHECK
  305.                                 if( 0xFFFFFFFF == bits )
  306.                                 {
  307.                                         #ifdef DBG
  308.                                         printf("line %d\n",__LINE__);
  309.                                         #endif
  310.                                         goto NO_BITS_HST;
  311.                                 }
  312. #endif                                                                                
  313.                                 switch( bits&3 )
  314.                                 {
  315.                                 case 0: // special cases
  316.  
  317.                                         bits = depack_getbits(1,DEPACK_GETBITS_NEXT);
  318. #ifdef DPK_CHECK
  319.                                         if( 0xFFFFFFFF == bits )
  320.                                         {
  321.                                                 #ifdef DBG
  322.                                                 printf("line %d\n",__LINE__);
  323.                                                 #endif
  324.                                                 goto NO_BITS_HST;
  325.                                         }
  326. #endif
  327.                                         if( bits&1 ) // %011 001abcd<byte> - insertion match, displacements -1..-16
  328.                                         {
  329.                                                 bits = depack_getbits(4,DEPACK_GETBITS_NEXT);
  330. #ifdef DPK_CHECK
  331.                                                 if( 0xFFFFFFFF == bits )
  332.                                                 {
  333.                                                         #ifdef DBG
  334.                                                         printf("line %d\n",__LINE__);
  335.                                                         #endif
  336.                                                         goto NO_BITS_HST;
  337.                                                 }
  338. #endif
  339.                                                 length = (-3); // mark insertion match
  340.  
  341.                                                 skipdisp = 1; // prepare displacement
  342.                                                 disp = (-16) | (bits&15);
  343.                                         }
  344.                                         else
  345.                                         {
  346.                                                 bits = depack_getbits(1,DEPACK_GETBITS_NEXT);
  347. #ifdef DPK_CHECK
  348.                                                 if( 0xFFFFFFFF == bits )
  349.                                                 {
  350.                                                         #ifdef DBG
  351.                                                         printf("line %d\n",__LINE__);
  352.                                                         #endif
  353.                                                         goto NO_BITS_HST;
  354.                                                 }
  355. #endif
  356.                                                 if( bits&1 ) // %011 0001abcd - copy-many-bytes
  357.                                                 {
  358.                                                         bits = depack_getbits(4,DEPACK_GETBITS_NEXT);
  359. #ifdef DPK_CHECK
  360.                                                         if( 0xFFFFFFFF == bits )
  361.                                                         {
  362.                                                                 #ifdef DBG
  363.                                                                 printf("line %d\n",__LINE__);
  364.                                                                 #endif
  365.                                                                 goto NO_BITS_HST;
  366.                                                         }
  367. #endif
  368.                                                         length = ((bits&15)+6)<<1;
  369.                                                         skipdisp = 1;
  370.                                                         docopy = 1;
  371.                                                 }
  372.                                                 else // %011 0000abcdefg[<byte>] - longer lengthes
  373.                                                 {
  374.                                                         bits = depack_getbits(7,DEPACK_GETBITS_NEXT);
  375. #ifdef DPK_CHECK
  376.                                                         if( 0xFFFFFFFF == bits )
  377.                                                         {
  378.                                                                 #ifdef DBG
  379.                                                                 printf("line %d\n",__LINE__);
  380.                                                                 #endif
  381.                                                                 goto NO_BITS_HST;
  382.                                                         }
  383. #endif
  384.                                                         bits &= 127;
  385.  
  386.                                                         if( bits==15 ) // stop depack
  387.                                                         {
  388.                                                                 stop=1;
  389.                                                         }
  390.                                                         else if( bits>15 ) // 16..127
  391.                                                         {
  392.                                                                 length = bits;
  393.                                                         }
  394.                                                         else // 0..14: longer lengthes
  395.                                                         {
  396.                                                                 byte = depack_getbyte(DEPACK_GETBYTE_NEXT);
  397. #ifdef DPK_CHECK
  398.                                                                 if( 0xFFFFFFFF == byte ) goto NO_BYTE_HST;
  399. #endif
  400.                                                                 length = (bits<<8) + (byte&0x00FF);
  401.                                                         }
  402.                                                 }
  403.                                         }
  404.                                         break;
  405.                                 case 1: // %01101
  406.                                         length = 4;
  407.                                         break;
  408.                                 case 2: // %01110
  409.                                         length = 5;
  410.                                         break;
  411.                                 case 3: // variable length (6-15), %01111...
  412.  
  413.                                         length = 6;
  414.                                         do
  415.                                         {
  416.                                                 bits = depack_getbits(2,DEPACK_GETBITS_NEXT);
  417. #ifdef DPK_CHECK
  418.                                                 if( 0xFFFFFFFF == bits )
  419.                                                 {
  420.                                                         #ifdef DBG
  421.                                                         printf("line %d\n",__LINE__);
  422.                                                         #endif
  423.                                                         goto NO_BITS_HST;
  424.                                                 }
  425. #endif                                                                                  
  426.                                                 bits &= 3;
  427.                                                 length += bits;
  428.  
  429.                                         } while( (bits==3) && (length<15) );
  430.                                         break;
  431.                                 }
  432.                         }
  433.  
  434.                         if( (!stop) && (!skipdisp) && (!docopy) )
  435.                         {
  436.                                 // extract displacement
  437.  
  438.                                 switch( disptype )
  439.                                 {
  440.                                 case DISP_COMMON:
  441.  
  442.                                         bits = depack_getbits(2,DEPACK_GETBITS_NEXT);
  443. #ifdef DPK_CHECK
  444.                                         if( 0xFFFFFFFF == bits )
  445.                                         {
  446.                                                 #ifdef DBG
  447.                                                 printf("line %d\n",__LINE__);
  448.                                                 #endif
  449.                                                 goto NO_BITS_HST;
  450.                                         }
  451. #endif                                                                                  
  452.                                         bits &= 3;
  453.                                         if( !bits ) // %00<byte> - fe00..feff
  454.                                         {
  455.                                                 disp = (-512);
  456.                                                 disptype=DISP_PLUSBYTE; // we fall in next section and there is check
  457.                                                 __attribute__((fallthrough));
  458.                                                 // NO break!
  459.                                         }
  460.                                         else if( bits==1 ) // %01<byte> - ff00..ffdf
  461.                                         {
  462.                                                 disp = (-256);
  463.                                                 __attribute__((fallthrough));
  464.                                                 // NO break!
  465.                                                 // no check for byte in range e0..ff here - but in next switch section!
  466.                                         }
  467.                                         else if( bits==2 ) // %10abcde - ffe0..ffff
  468.                                         {
  469.                                                 bits = depack_getbits(5,DEPACK_GETBITS_NEXT);
  470. #ifdef DPK_CHECK
  471.                                                 if( 0xFFFFFFFF == bits )
  472.                                                 {
  473.                                                         #ifdef DBG
  474.                                                         printf("line %d\n",__LINE__);
  475.                                                         #endif
  476.                                                         goto NO_BITS_HST;
  477.                                                 }
  478. #endif                                                                                  
  479.                                                 disp = (-32) | (bits&31);
  480.  
  481.                                                 break;
  482.                                         }
  483.                                         else // %11... - expanding displacement
  484.                                         {
  485.                                                 bits = depack_getbits(expbitlen,DEPACK_GETBITS_NEXT);
  486. #ifdef DPK_CHECK
  487.                                                 if( 0xFFFFFFFF == bits )
  488.                                                 {
  489.                                                         #ifdef DBG
  490.                                                         printf("line %d\n",__LINE__);
  491.                                                         #endif
  492.                                                         goto NO_BITS_HST;
  493.                                                 }
  494. #endif                                                                                  
  495.                                                 //disp = (-1)<<expbitlen;
  496.                                                 disp = (-1UL)<<expbitlen;
  497.                                                 disp |= (bits&(~disp));
  498.  
  499.                                                 disp <<= 8;
  500.  
  501.                                                 disptype = DISP_PLUSBYTE;
  502.                                                 __attribute__((fallthrough));
  503.                                                 // NO break!
  504.                                         }
  505.  
  506.                                 case DISP_PLUSBYTE:
  507.                                         byte = depack_getbyte(DEPACK_GETBYTE_NEXT);
  508. #ifdef DPK_CHECK
  509.                                         if( 0xFFFFFFFF == byte ) goto NO_BYTE_HST;
  510. #endif
  511.                                         if( disptype==DISP_COMMON ) // if we here from previous section of switch()
  512.                                         {                           // we must check for insertion match!
  513.  
  514.                                                 if( byte<0x00E0 ) // ff00..ffdf
  515.                                                 {
  516.                                                         disp = (-256) | (byte&0x00FF);
  517.                                                 }
  518.                                                 else // insertion match - xor 3
  519.                                                 {
  520.                                                         length = (-3); // mark insertion match
  521.  
  522.                                                         byte = ((byte<<1)&0x00FE) | ((byte>>7)&0x01); // byte<<<1
  523.                                                         byte ^= 0x03;
  524.                                                         byte -= 15;
  525.  
  526.                                                         disp = (-256) | (byte&0x00FF);
  527.                                                 }
  528.                                         }
  529.                                         else
  530.                                         {
  531.                                                 disp = disp + (byte&0x00FF);
  532.                                         }
  533.  
  534.                                         break;
  535.  
  536.                                 case DISP_ABCDE:
  537.                                         bits = depack_getbits(5,DEPACK_GETBITS_NEXT);
  538. #ifdef DPK_CHECK
  539.                                         if( 0xFFFFFFFF == bits )
  540.                                         {
  541.                                                 #ifdef DBG
  542.                                                 printf("line %d\n",__LINE__);
  543.                                                 #endif
  544.                                                 goto NO_BITS_HST;
  545.                                         }
  546. #endif
  547.                                         disp = (-32) | (bits&31);
  548.  
  549.                                         break;
  550.  
  551.                                 default:
  552. #ifdef DPK_CHECK
  553.  #ifdef DPK_REPERR
  554.                                         printf("mhmt-depack-hrust.c:{} - Wrong displacement in disptype!\n");
  555.  #endif
  556.                                         return 0;
  557. #endif
  558.                                         break;
  559.                                 }
  560.                         }
  561.  
  562.  
  563. #ifdef DPK_CHECK
  564.                         if( success && (!docopy) && (!stop) && ((ULONG)(-disp)>wrk.maxwin) )
  565.                         {
  566. WRONG_DISP_HST:
  567.  #ifdef DPK_REPERR
  568.                                 printf("mhmt-depack-hrust.c:{} - Wrong lookback displacement of %d, greater than maxwin\n",(-disp) );
  569.  #endif
  570.                                 return 0;
  571.                         }
  572. #endif
  573.  
  574.  
  575.                         if( docopy && (!stop) )
  576.                         {
  577.                                 #ifdef DBG
  578.                                         printf("copy.len=%d\n",length);
  579.                                 #endif
  580.                                 for(i=0;i<length;i++)
  581.                                 {
  582.                                         byte = depack_getbyte(DEPACK_GETBYTE_NEXT);
  583. #ifdef DPK_CHECK
  584.                                         if( 0xFFFFFFFF == byte ) goto NO_BYTE_HST;
  585. #endif
  586.  
  587.  
  588. #ifdef DPK_DEPACK
  589.                                         success = success && depack_outbyte( (UBYTE)(0x00FF&byte), DEPACK_OUTBYTE_ADD );
  590. #endif
  591.                                 }
  592.                         }
  593.                         else if( (!docopy) && (!stop) )// not do-copy
  594.                         {
  595.                                 if( length!=(-3) )
  596.                                 {
  597.                                         #ifdef DBG
  598.                                         if(length) printf("match.len=%d,disp=%d\n",length,disp);
  599.                                         #endif
  600.  
  601. #ifdef DPK_DEPACK
  602.                                         if( length )
  603.                                                 success = success && depack_repeat(disp,length);
  604. #endif
  605.                                 }
  606.                                 else // (-3)
  607.                                 {
  608.                                         byte = depack_getbyte(DEPACK_GETBYTE_NEXT);
  609. #ifdef DPK_CHECK
  610.                                         if( 0xFFFFFFFF == byte ) goto NO_BYTE_HST;
  611. #endif
  612.                                         #ifdef DBG
  613.                                                 printf("insert-match.len=%d,disp=%d\n",(-length),disp);
  614.                                         #endif
  615.  
  616.  
  617. #ifdef DPK_DEPACK
  618.                                         success = success && depack_repeat(disp,1);
  619.                                         success = success && depack_outbyte( (UBYTE)(0x00FF&byte), DEPACK_OUTBYTE_ADD );
  620.                                         success = success && depack_repeat(disp,1);
  621. #endif
  622.                                 }
  623.  
  624.                         }
  625.         }
  626.  
  627.  
  628.         #ifdef DBG
  629.         printf("got stop symbol!\n");
  630.         #endif
  631.  
  632.  
  633.         //manage zxheader again (copy to the end of output)
  634. #ifdef DPK_DEPACK
  635.         if( wrk.zxheader )
  636.         {
  637.                 check = depack_getbyte(DEPACK_GETBYTE_REWIND);
  638.  #ifdef DPK_CHECK
  639.                 if( 0xFFFFFFFF == check )
  640.                 {
  641.   #ifdef DPK_REPERR
  642.                         printf("mhmt-depack-hrust.c:{} - Can't rewind input stream!\n");
  643.   #endif
  644.                         return 0;
  645.                 }
  646.  #endif
  647.  
  648.                 for(i=0;i<6;i++) // skip bytes
  649.                 {
  650.                         byte = depack_getbyte(DEPACK_GETBYTE_NEXT);
  651.  #ifdef DPK_CHECK
  652.                         if( 0xFFFFFFFF == check ) goto NO_BYTE_HST;
  653.  #endif
  654.                 }
  655.                 // place 6 bytes of header to the end
  656.                 for(i=0;i<6;i++)
  657.                 {
  658.                         byte = depack_getbyte(DEPACK_GETBYTE_NEXT);
  659.  #ifdef DPK_CHECK
  660.                         if( 0xFFFFFFFF == check ) goto NO_BYTE_HST;
  661.  #endif
  662.                         success = success && depack_outbyte( (UBYTE)(0x00FF&byte), DEPACK_OUTBYTE_ADD );
  663.                 }
  664.         }
  665. #endif
  666.  
  667.         return success;
  668. }
  669.  
  670.