Page 1 of 1

Division by zero when expanding table

Posted: Thu Nov 12, 2020 7:02 am
by HAiDA
I have problem with exception Division by zero when I expanding table. Exception is trigged in unit RVGrIn.pas -

Code: Select all

procedure TRVGraphicInterface.ExpandSpacesInCoords
..
begin
  if (SpaceCount <= 0) or (ExtraSpacing = 0) then
    exit;
  PCoordsL2 := PRVIntegerArray(PCoordsL);
  PCoordsR2 := PRVIntegerArray(PCoordsR);
  PCP2 := PRVIntegerArray(PCP);

  wpc := Str;
  for i := 0 to Length - 1 do
    if wpc[i] = ' ' then
    begin
      ExtraDX := ExtraSpacing div SpaceCount; <--
      ShiftCoords(PCoordsL2^[i], ExtraDX);
      dec(SpaceCount);
      dec(ExtraSpacing, ExtraDX);
    end;
end;
My method on comparing and expanding table (MailMerge table - adding or removing rows) is

Code: Select all

function Tf_RVEditor2.FillTable(table: TRVTableItemInfo;
  ADesign: boolean): boolean;
var
  r, c: Integer;
  RVData: TCustomRVData;
  i, j: Integer;
  _Stream: TMemoryStream;
  _Layout: TRVLayoutInfo;
  _Color: TColor;
  _BackGround: TRVBackground;
  AppendRowCount: Integer;
  ParItem: TRVParamsItem;
  FieldName: string;
  _Table: string;
  _Column: string;
  _Row: Integer;
  _Data: string;
  FieldNameS: string;
  _TableS: string;
  _ColumnS: string;
  _RowS: Integer;
  _DataS: string;
  tmpRowCount: Integer;
  _CellIsSame: boolean;
  _FirstFieldRow: boolean;
  rs: Integer;
  _ItemNo, _IData: Integer;
begin
  Result := True;
  if ADesign then
  begin
    // Odmázání řádku
    r := 0;
    _CellIsSame := True;
    rs := 0;
    AppendRowCount := 0;
    _ItemNo := ActiveEditor.RichViewEdit.GetItemNo(table);
    if _ItemNo <> -1 then
    begin
      ActiveEditor.RichViewEdit.BeginUndoGroup(rvutModifyItem);
      ActiveEditor.RichViewEdit.SetUndoGroupMode(True);
      ActiveEditor.RichViewEdit.BeginItemModify(_ItemNo, _IData);
    end;
    try
      while r < table.Rows.Count do
      begin
        table.SelectRows(0, table.Rows.Count);
        _FirstFieldRow := False;
        for c := 0 to Pred(table.Rows[r].Count) do
        begin
          if table.Cells[r, c] <> nil then
          begin
            RVData := table.Cells[r, c].GetRVData;
            for i := 0 to Pred(RVData.Items.Count) do
              if TagFieldName(RVData.GetItemTag(i), FieldName) and
                (TRVParamsItem.ParseFieldNameEx(FieldName, _Column, _Table, _Row, _Data)) and
                (_Table <> '') and (_Row = -1) then
              begin
                AppendRowCount := StrToInt(_Data);
                _FirstFieldRow := True;
                Break;
              end;
            if _FirstFieldRow then
              Break;
          end;
        end;
        if _FirstFieldRow then
        begin
          for c := 0 to Pred(table.Rows[r].Count) do
          begin
            if table.Cells[r, c] <> nil then
            begin
              for j := 1 to Pred(AppendRowCount) do
              begin
                rs := r + j;
                if rs > Pred(table.Rows.Count) then
                  Break;
                _CellIsSame := True;
                if not((table.Cells[rs, c] <> nil) and (table.Cells[rs, c].GetRVData.ItemCount = table.Cells[r,
                  c].GetRVData.ItemCount)) then
                  _CellIsSame := False
                else
                begin
                  // Porovnavani obsahu bunek.
                  for i := 0 to Pred(table.Cells[rs, c].ItemCount) do
                  begin
                    if TagFieldName(table.Cells[rs, c].GetItemTag(i), FieldNameS) and
                      TRVParamsItem.ParseFieldName(FieldNameS, _ColumnS, _TableS, _RowS) and (_TableS <> '') then
                    begin
                      // porovnani slučovacích polí.
                      if not((table.Cells[r, c].ItemCount > i) and TagFieldName(table.Cells[r, c].GetItemTag(i),
                        FieldName) and TRVParamsItem.ParseFieldName(FieldName, _Column, _Table, _Row) and
                        (_ColumnS = _Column) and (_TableS = _Table) and (_RowS <> -1)) then
                        _CellIsSame := False;
                    end
                    else
                      // porovnani jiných položek.
                      if not((table.Cells[r, c].GetItemText(i) = table.Cells[rs, c].GetItemText(i))) then
                        _CellIsSame := False;
                  end;
                end;
                if not _CellIsSame then
                  Break;
              end;
            end;
            if not _CellIsSame then
              Break;
          end;
          if (not _CellIsSame) and (not SilentMode) then
          begin
            table.Select(rs, c, 0, 0);
            msgInfo('Aktuální tabulka byla změněna.', 'Po dokončení operaci prosím zkontrolujte šablonu.', 'Informace');
            exit;
          end;
          if (table.Rows.Count > succ(r)) and (AppendRowCount > 1) then
          begin
            table.DeleteRows(r + 1, Pred(AppendRowCount), False);
          end;
        end;
        inc(r);
      end;
    finally
      if _ItemNo <> -1 then
      begin
        ActiveEditor.RichViewEdit.SetUndoGroupMode(False);
        ActiveEditor.RichViewEdit.EndItemModify(_ItemNo, _IData);
      end;
    end;
    table.Changed;
  end
  else
  begin
    // Přidání řádků
    _Stream := TMemoryStream.Create;
    try
      _ItemNo := ActiveEditor.RichViewEdit.GetItemNo(table);
      if _ItemNo <> -1 then
      begin
        ActiveEditor.RichViewEdit.BeginUndoGroup(rvutModifyItem);
        ActiveEditor.RichViewEdit.SetUndoGroupMode(True);
        ActiveEditor.RichViewEdit.BeginItemModify(_ItemNo, _IData);
      end;
      try
        r := 0;
        while r < table.Rows.Count do
        begin
          // zjisteni kolik radku bude treba do tabulky pridat
          AppendRowCount := 0;
          for c := 0 to Pred(table.Rows[r].Count) do
          begin
            if table.Cells[r, c] <> nil then
            begin
              RVData := table.Cells[r, c].GetRVData;
              for i := 0 to Pred(RVData.Items.Count) do
              begin
                if TagFieldName(RVData.GetItemTag(i), FieldName)
                  and (TRVParamsItem.ParseFieldName(FieldName, _Column, _Table, _Row))
                  and (_Table <> '') and (_Row = -1) then
                begin
                  if FParams.existParamByFieldName(FieldName) then
                  begin
                    ParItem := FParams.ParamByFieldName(FieldName);
                    if Assigned(ParItem) and (ParItem.BelongsToTable) then
                    begin
                      tmpRowCount := ParItem.Values.Count;
                      if tmpRowCount > AppendRowCount then
                        AppendRowCount := tmpRowCount;
                    end;
                  end
                  else
                    AppendRowCount := 1;
                end;
              end;
            end;
          end;
          // if AppendRowCount > 0 then se jedna o řádek na kterém jsou tabulková slučovací pole
          if AppendRowCount > 0 then
          begin
            // Vlastni pridani radku
            table.InsertRows(r + 1, AppendRowCount - 1, r, False);
            table.Changed;
            // Kopirování obsahu buňek.
            for c := 0 to Pred(table.Rows[r].Count) do
              if table.Cells[r, c] <> nil then
              begin
                for i := 0 to Pred(table.Cells[r, c].ItemCount) do
                  if TagFieldName(table.Cells[r, c].GetRVData.GetItemTag(i), FieldNameS) then
                    if TRVParamsItem.ParseFieldName(FieldNameS, _ColumnS, _TableS, _RowS) then
                      table.Cells[r, c].SetItemTag(i, TRVParamsItem.ArrangeFieldName(_ColumnS, _TableS, _RowS,
                        IntToStr(AppendRowCount)));
                _Stream.Size := 0;
                _Layout := ActiveEditor.RichViewEdit.CreateLayoutInfo;
                try
                  table.Cells[r, c].SaveRVFToStream(_Stream, False, ActiveEditor.RichViewEdit.Color,
                    ActiveEditor.RichViewEdit.Background, _Layout);
                  for j := 1 to Pred(AppendRowCount) do
                  begin
                    rs := r + j;
                    _Stream.Position := soFromBeginning;
                    if table.Cells[rs, c] = nil then
                      table.UnmergeCells(r, c, 1, AppendRowCount, True, False);
                    _Color := ActiveEditor.RichViewEdit.Color;
                    _BackGround := ActiveEditor.RichViewEdit.Background;
                    table.Cells[rs, c].LoadRVFFromStream(_Stream, _Color, _BackGround, _Layout, nil, nil);
                    for i := 0 to Pred(table.Cells[rs, c].ItemCount) do
                      if TagFieldName(table.Cells[rs, c].GetRVData.GetItemTag(i), FieldNameS) then
                        if TRVParamsItem.ParseFieldNameEx(FieldNameS, _ColumnS, _TableS, _RowS, _DataS) then
                          table.Cells[rs, c].SetItemTag(i, TRVParamsItem.ArrangeFieldName(_ColumnS, _TableS, j,
                            _DataS));
                  end;
                finally
                  FreeAndNil(_Layout);
                end;
              end;
          end;
          inc(r);
        end;
      finally
        if _ItemNo <> -1 then
        begin
          ActiveEditor.RichViewEdit.SetUndoGroupMode(False);
          ActiveEditor.RichViewEdit.EndItemModify(_ItemNo, _IData);
        end;
      end;
    finally
      FreeAndNil(_Stream);
    end;
  end;
end;
Do you see anything suspicious that will cause an error in your unit?

Re: Division by zero when expanding table

Posted: Thu Nov 12, 2020 7:39 am
by Sergey Tkachenko
Can you send me a project reproducing this problem?
It's too hard to check this large code in a browser.
I do not understand how division by zero can occur here, because a divider (SpaceCount) is checked at the beginning of this method.

Re: Division by zero when expanding table

Posted: Thu Nov 12, 2020 8:00 am
by HAiDA
I try make example. SpaceCoint is checked at the beginnig, but follows for i := 0 to Length - 1 do and dec(SpaceCount);

Re: Division by zero when expanding table

Posted: Thu Nov 12, 2020 9:08 am
by Sergey Tkachenko
Well, yes.

But there is something wrong here.

SpaceCount must be equal to the count of space characters in the string.
Since it is decremented after encountering a space character, it must become zero only when there is no more space characters, so no more divisions may occur.

So, somehow text and formatting became out of sync. I need a test example to understand how it can be possible.