topbanner_forum
  *

avatar image

Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
  • Thursday March 28, 2024, 1:56 pm
  • Proudly celebrating 15+ years online.
  • Donate now to become a lifetime supporting member of the site and get a non-expiring license key for all of our programs.
  • donate

Author Topic: Insert Char into String - I "Hit the Wall" ...again.  (Read 9424 times)

Stoic Joker

  • Honorary Member
  • Joined in 2008
  • **
  • Posts: 6,646
    • View Profile
    • Donate to Member
Insert Char into String - I "Hit the Wall" ...again.
« on: August 27, 2008, 10:32 AM »
Okay in attempting what's supposed to be a simple function...I have once again been thwarted at every turn.

(As usual I'm working in pure Win32 API C++)

I'm grabbing a block of text from an edit control, this is then passed to a function that puts it together with other bits of info that are used to build a SQL Query. The SQL Query is then fired against the db where it hopefully doesn't fail (Error checking abounds...).

Simple Right? ...Ha!

The problem is that if someone enters a possessive like "Joker's", the apostrophe which is a SQL control character causes the Query/function to fail. So I'm trying to replace every instance of ' with '' (Which is 2 apostrophes Not a double quote). Therein lying the rub...

I have spent the last 3 days trying the find a way to walk the string and insert a 2nd apostrophe anywhere there is a first. Everything that Google turns up referrers to the insert(...) function in namespace std; ... That's nice... except my use of the StringSafe routines (in the other 80 pages of code...) causes the compiler to spew errors for about a half an hour due to the inclusion of string.h (required by namespace std; ) .

I've seen this type of function before where the string to parsed through a series of pointers... but I never have quite understood it. ...Hence my inability to use it effectively.

So... Here's the block of poo I'm working with which will hopefully convey what I'm after:
Code: C++ [Select]
  1. void CleanString(char *szDirty) {
  2.         char  *p;
  3.   p =  szDirty;
  4.   if(p == 0) {
  5.           return;
  6.   }else{
  7.           while(*p) {
  8.                   if(*p == '\'') {
  9.                           MessageBox(0, p, "Found IT!", MB_OK);
  10.                           *p += '\'';
  11.                           MessageBox(0, p, "*pTmp++ = ?", MB_OK);
  12.                           p = CharNext(p);
  13. //                        pTmp += 1;
  14.                   }else{
  15.                           p = CharNext(p);
  16.                   }
  17.           }
  18.           *p = 0;
  19.           MessageBox(0, p, "*pTmp = 0", MB_OK);
  20.   }
  21. }

The MessageBoxes are only there for debugging purposes so I can tell what it's interpretation of what I just told it was.

Everything I try either drops the 2nd apostrophe or the s that comes after it. *Sigh*

What am I doing wrong?

Thank You,
Stoic Joker

mwb1100

  • Supporting Member
  • Joined in 2006
  • **
  • Posts: 1,645
    • View Profile
    • Donate to Member
Re: Insert Char into String - I "Hit the Wall" ...again.
« Reply #1 on: August 27, 2008, 10:59 AM »
The inster() method is part of the C++ string class, so you'd need to include <string>  - not <string.h> which gets you the good, old standard C string functions (which, as you find, are deprecated in MSVC 9 for the most part as being unsafe).  Since you're using raw strings instead of the string class, the insert() method will not be much help unless you're willing to move to using the string class.  That might be a worthwhile thing, but it might be a lot of work.

If you're going to insert a character in a raw string, you'll need to move the characters in the tail end of string (after the insertion point) over one character each.  So before line 10 in your example, you'll need something equivalent to:

Code: C++ [Select]
  1. memmove( p + 1, p, strlen( p) + 1)

But you'll need to adjust that bit of code to use the SafeString equivalent to memmove().  Note that you need memmove() semantics - not memcpy() - since the source and destination buffers overlap.

Stoic Joker

  • Honorary Member
  • Joined in 2008
  • **
  • Posts: 6,646
    • View Profile
    • Donate to Member
Re: Insert Char into String - I "Hit the Wall" ...again.
« Reply #2 on: August 27, 2008, 11:32 AM »
 :wallbash: :huh: :graduate:

And the Correct Answer is ... What ^^he^^ said.

I pasted in the example you gave, compiled, tossed in a buffer chocking block of text, and it worked perfectly!!!

So I'll assume memmove is StringSafe ... Safe (as it are Working).


Thank You!

(I think I'll go outside now and see what sun light looks like... ;))

mwb1100

  • Supporting Member
  • Joined in 2006
  • **
  • Posts: 1,645
    • View Profile
    • Donate to Member
Re: Insert Char into String - I "Hit the Wall" ...again.
« Reply #3 on: August 27, 2008, 01:06 PM »
So I'll assume memmove is StringSafe ... Safe (as it are Working).

Uh oh.... my example is not exactly safe.  For simplicity's sake there were a couple things left out that you may want to check:

  • the example I gave does not ensure that there's enough buffer for the memmove() - if the string passed in to the CleanString() function happens to fill its allocated memory exactly, the memmove will overrun the buffer (which is exactly the type of problem that the SafeString routines were intended to prevent).  Since the buffer size is not passed in to CleanString() I'm not sure that you can grow the string in place safely.  You may need to change the CleanString() interface to include the buffer size and change the memmove() call to ensure that the buffer is not overrun and that the resulting expanded string is always null terminated.
  • The memmove() is not Unicode aware.  The CleanString() function you presented is also not Unicode aware, but to make it at least slightly easier to port, the memmove() call should probably look like "memmove( p + 1, p, (_tcslen( p) + 1) * sizeof (*p))"

Stoic Joker

  • Honorary Member
  • Joined in 2008
  • **
  • Posts: 6,646
    • View Profile
    • Donate to Member
Re: Insert Char into String - I "Hit the Wall" ...again.
« Reply #4 on: August 27, 2008, 03:00 PM »
LOL Yes I caught that part, By "Safe" I meant the functions didn't collide/conflict/refuse to compile.

The edit control the text comes from is input size limited to 500 characters and the buffer is 512 - I'm assuming nobody will use that many apostrophes...

If I have CleanString() stop before adding too many characters the SQL query/very next function will fail anyway...So it's kind of a Catch22. The SQL query string buffer is (defined in the main header file as) 2048 because SQL queries tend to be large & I hate having to define buffer sizes locally and then remember how big they were 10 pages later when I try to toss something at the function.

Dynamic buffer allocation is one of those things I never have figured out so resizing on the fly might take a while (Suggestions I'm open for...).

I wasn't thinking about the unicode part as this is a in-house only app, and nobody is going to by typing Chinese into it ... but that is a bad habbit I'm getting into.


mwb1100

  • Supporting Member
  • Joined in 2006
  • **
  • Posts: 1,645
    • View Profile
    • Donate to Member
Re: Insert Char into String - I "Hit the Wall" ...again.
« Reply #5 on: August 27, 2008, 05:03 PM »
Dynamic buffer allocation is one of those things I never have figured out so resizing on the fly might take a while (Suggestions I'm open for...).

If you're using C++ I'd strongly consider using the string class (or the similar, but different, MFC/ATL CString class).  Even if you don't use any other aspect of C++ having those classes deal with the buffer management of the string data is an immense help.  And since the classes provide an easy way to get a null terminated, C-style string (using the c_str() method with std::string - don't remember what it is in the CString class) it's easy to have the strings interact with most Win32 and other C-oriented APIs. 

The only time it becomes a problem is when the API wants a buffer that it's going to copy a string into.  Or returns a pointer to a string that you then have to free using some other API function.  For those situations I'll often write a small wrapper that allocates the buffer (and frees it when done), calls the API then packages the result in a string object that gets returned by the wrapper.  There may be an extra heap allocation and a string copy in there, but I think the resulting ease and safety of use is worth it in almost all cases.

f0dder

  • Charter Honorary Member
  • Joined in 2005
  • ***
  • Posts: 9,153
  • [Well, THAT escalated quickly!]
    • View Profile
    • f0dder's place
    • Read more about this member.
    • Donate to Member
Re: Insert Char into String - I "Hit the Wall" ...again.
« Reply #6 on: August 27, 2008, 05:59 PM »
Dude, you're passing a "char *string" to your function. Go redesign the code now. Either you pass a std::string (or std::wstring), or you pass along a buffer-length argument... and make sure to check for it.

Also, instead of trying to sanitize strings for use with SQL queries, have a look at bound arguments - much safer.
- carpe noctem

Stoic Joker

  • Honorary Member
  • Joined in 2008
  • **
  • Posts: 6,646
    • View Profile
    • Donate to Member
Re: Insert Char into String - I "Hit the Wall" ...again.
« Reply #7 on: August 28, 2008, 04:27 PM »
Also, instead of trying to sanitize strings for use with SQL queries, have a look at bound arguments - much safer.

"bound arguments"? -(never heard of them)- Where is it I would start looking at/for these?


edit by jgpaiva: fixed quote tag
« Last Edit: August 28, 2008, 07:39 PM by jgpaiva »

f0dder

  • Charter Honorary Member
  • Joined in 2005
  • ***
  • Posts: 9,153
  • [Well, THAT escalated quickly!]
    • View Profile
    • f0dder's place
    • Read more about this member.
    • Donate to Member
Re: Insert Char into String - I "Hit the Wall" ...again.
« Reply #8 on: August 28, 2008, 06:03 PM »
I'm afraid you need to go slightly SQL server specific to do bound arguments, but that can obviously be abstracted away so you don't tie yourself down to just one SQL Server. The idea is that instead of inserting quoted strings (and being vulnerable to SQL injection), you refer to your strings symbolically in the SQL statements, and bind your actualy strings (or other data types) using the API your SQL library. Much safer.

I'm heading off for bed, so I'm afraid I don't have any links handy :)
- carpe noctem