Author Topic: Create a binary file from scratch!  (Read 9127 times)

0 Members and 1 Guest are viewing this topic.

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Create a binary file from scratch!
« on: May 24, 2012, 05:16:53 AM »
After this discussion with Lee I thought it would be impossible to write a binary file from scratch. But then I had a tiny brainwave: It can be done if you use a a small binary file containing all byte values (0 - 255 inclusive) as a "lookup table".

Most likely this is a case of reinventing the wheel, but if you want to give it a try:
Put the two files from the zip in the same folder.
Open a dwg in that folder and load the lisp.
The test function (c:TestFlag) should create a small bmp file in the current folder.

Edit: Typo.
« Last Edit: May 24, 2012, 01:46:24 PM by roy_043 »

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Create a binary file from scratch!
« Reply #1 on: May 24, 2012, 11:29:53 AM »
Why not use the same principle as MP's over here: http://www.theswamp.org/index.php?topic=17465.0

It could easily be modified to work with a list of bytes (as long as each integer in the list is 0-255):
Code: [Select]
(defun BinFile-Write  (FileName lst / fso stream file result)
  (vl-catch-all-apply
    '(lambda (/ size)
       (setq fso (vlax-create-object "Scripting.FileSystemObject")
             stream (vlax-invoke fso 'OpenTextFile FileName 2 :vlax-true 0))
       (vlax-invoke stream 'Write (vl-list->string lst))
       (vlax-invoke stream 'Close)
       (setq file (vlax-invoke fso 'GetFile FileName)
             result (vlax-get file 'Size))))
  (if stream
    (vlax-release-object stream))
  (if file
    (vlax-release-object file))
  (if fso
    (vlax-release-object fso))
  result)
« Last Edit: May 24, 2012, 11:35:03 AM by irneb »
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Create a binary file from scratch!
« Reply #2 on: May 24, 2012, 01:42:41 PM »
Why not use the same principle as MP's over here: http://www.theswamp.org/index.php?topic=17465.0

I have tried that:
So I am using MP's (_WriteStream). But somehow the conversion to text that his write function requires causes trouble. In my test only 290 bytes instead of 440 - 60 = 380 bytes were written.

Basically MP's code is unable to write a byte with a value of zero. If I try to create the Flag.bmp with your version of MP's code I get a file of 4 bytes instead of 286 bytes.

Please let me know if your testing shows a different result.

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Create a binary file from scratch!
« Reply #3 on: May 24, 2012, 03:04:39 PM »
To write a null byte in lisp use char code 256
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Create a binary file from scratch!
« Reply #4 on: May 24, 2012, 03:33:45 PM »
To write a null byte in lisp use char code 256

If I modify the code in irneb's contribution to replace all zero's in the list with 256:
Code: [Select]
(subst 256 0 lst)I again end up with a file of only 4 bytes, meaning the writing process stopped before the first null byte.

Does your suggestion work in Autocad?

Note:
Code: [Select]
(vl-list->string '(0 1 2 3)) => "\000\001\002\003"
(vl-list->string '(256 1 2 3)) => "\000\001\002\003"
« Last Edit: May 24, 2012, 03:38:26 PM by roy_043 »

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Create a binary file from scratch!
« Reply #5 on: May 24, 2012, 05:50:45 PM »
I have used this method in the past in AutoCAD, but I didn't use vlisp to accomplish it ...

For example:
Code: [Select]
(defun c:writefile()
  (setq fn (open "C:\\Users\\Keith\\Desktop\\testing.dat" "w")
i 1
x 10)
  (repeat 100 (write-char 256 fn))
  (while (< 0 x)
    (write-char i fn)
    (setq i (1+ i))
    (if (= i 257)
      (setq x (1- x)
    i 1)
    )
  )
  (close fn)
)
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Create a binary file from scratch!
« Reply #6 on: May 25, 2012, 03:12:13 AM »
@ Keith:

Using (write-char) doesn't do the trick in Bricscad:
Code: [Select]
(defun c:Test-write-char ( / file)
  (setq file (open (strcat (getvar 'dwgprefix) "test.bin") "w"))
  (repeat 8 (write-char   1 file))
  (repeat 8 (write-char 256 file)) ; Is not written to the file.
  (repeat 8 (write-char   2 file))
  (repeat 8 (write-char   0 file)) ; Is not written to the file.
  (repeat 8 (write-char   3 file))
  (close file)
)

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Create a binary file from scratch!
« Reply #7 on: May 25, 2012, 03:13:59 AM »
Are you sure you've copied my code correctly? Here's my full version (derived from MP's code):
Code - Auto/Visual Lisp: [Select]
  1.  
  2. (defun BinFile-Read  (FileName / fso stream file result)
  3.   (if (setq FileName (findfile FileName))
  4.     (vl-catch-all-apply
  5.       '(lambda (/ size)
  6.          (setq fso    (vlax-create-object "Scripting.FileSystemObject")
  7.                file   (vlax-invoke fso 'GetFile FileName)
  8.                stream (vlax-invoke fso 'OpenTextFile FileName 1 :vlax-false 0)
  9.                size   (vlax-get file 'Size)
  10.                result (vlax-invoke stream 'read size))
  11.          (vlax-invoke stream 'Close))))
  12.   (if stream
  13.     (vlax-release-object stream))
  14.   (if file
  15.     (vlax-release-object file))
  16.   (if fso
  17.     (vlax-release-object fso))
  18.   (if result
  19.     (vl-string->list result)))
  20.  
  21.  
  22. (defun BinFile-Write  (FileName lst / fso stream file result)
  23.   (vl-catch-all-apply
  24.     '(lambda (/ size)
  25.        (setq fso    (vlax-create-object "Scripting.FileSystemObject")
  26.              stream (vlax-invoke fso 'OpenTextFile FileName 2 :vlax-true 0))
  27.        (vlax-invoke stream 'Write (vl-list->string lst))
  28.        (vlax-invoke stream 'Close)
  29.        (setq file   (vlax-invoke fso 'GetFile FileName)
  30.              result (vlax-get file 'Size))))
  31.   (if stream
  32.     (vlax-release-object stream))
  33.   (if file
  34.     (vlax-release-object file))
  35.   (if fso
  36.     (vlax-release-object fso))
  37.   result)
And here's a test to confirm if the file is written correctly (without any substitutions):
Code: [Select]
_$ (setq lst nil n 256)
256
_$ (repeat n (setq lst (cons (setq n (1- n)) lst)))
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255)
_$ (length lst)
256
_$ (BinFile-Write "c:/temp/test1.bin" lst)
256
_$ (length (BinFile-Read "c:/temp/test1.bin"))
256
_$ (BinFile-Read "c:/temp/test1.bin")
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255)
Note if you use MP's writestream directly it's going to write the file in the default text format. On my system that's bigendian Unicode - i.e. the above file would have been 512 bytes. That's because he's using CreateTextFile which simply uses the default format. I've changed that to OpenTextFile with the option 0 to force using ASCII instead of whatever the default is.

Keith's code doesn't work for me:
Code - Auto/Visual Lisp: [Select]
  1. (defun BinFile-WriteChars  (FileName chars / f)
  2.   (if (and (setq FileName (findfile FileName)) (setq f (open FileName "w")))
  3.     (progn (foreach c  (mapcar '(lambda (c)
  4.                                   (cond ((< 0 c 256) c)
  5.                                         (t 256)))
  6.                                chars)
  7.              (write-char c f))
  8.            (close f))))
And the same test:
Code: [Select]
_$ lst
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255)
_$ (BinFile-WriteChars "c:/temp/test2.bin" lst)
nil
_$ (BinFile-Read "c:/temp/test2.bin")
nil
Perhaps it's something to do with my Win7-64-pro + ACad Vanilla 2012.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Create a binary file from scratch!
« Reply #8 on: May 25, 2012, 03:49:21 AM »
Keith's code doesn't work for me:...
Sorry I'm an idiot  :ugly: ... why did I think I should check if the file exists before I write to it?  :lmao:

The code should be:
Code - Auto/Visual Lisp: [Select]
  1. (defun BinFile-WriteChars  (FileName chars / f)
  2.   (if (setq f (open FileName "w"))
  3.     (progn (foreach c  (mapcar '(lambda (c)
  4.                                   (cond ((< 0 c 256) c)
  5.                                         (t 256)))
  6.                                chars)
  7.              (write-char c f))
  8.            (close f))))
And now the test works slightly better:
Code: [Select]
_$ (BinFile-WriteChars "c:/temp/test2.bin" lst)
nil
_$ (BinFile-Read "c:/temp/test2.bin")
(0 1 2 3 4 5 6 7 8 9 13 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255)
_$ (length (BinFile-Read "c:/temp/test2.bin"))
257
It's now 257 long since it writes a "\r\n" for each newline character ("\r" = 13, "\n" = 10).
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Create a binary file from scratch!
« Reply #9 on: May 25, 2012, 05:19:43 AM »
Are you sure you've copied my code correctly?
Yes, I am sure. :angel:

The fact that your code fails for me may well be a Bricscad thing.

OT:
What is the correct procedure for copying Auto/Visual Lisp formatted code from the forum? If I do a simple copy/paste I get the line numbers in the result.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Create a binary file from scratch!
« Reply #10 on: May 25, 2012, 05:56:59 AM »
OT:
What is the correct procedure for copying Auto/Visual Lisp formatted code from the forum? If I do a simple copy/paste I get the line numbers in the result.
Strange, when I do so the numbers are omitted. Perhaps it's a browser thing. I'm using FireFox 12.0 and then pasting directly into Command Line / VLIDE / NotePad / NotePad+ / SciTE - nowhere do I get those line numbers pasted, even if I selected some text before and/or after the code block.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Create a binary file from scratch!
« Reply #11 on: May 25, 2012, 06:02:38 AM »
The fact that your code fails for me may well be a Bricscad thing.
Then I'm guessing its BC's implementation of the vl-string->list and vl-list->string functions. AC's seem to take 0 values perfectly, and it also doesn't screw with the 10 value ("\n") like the write-char / read-char does.

Edit: I've tried using my own rolled out versions of those:
Code - Auto/Visual Lisp: [Select]
  1. (defun lst->str (lst /) (apply 'strcat (mapcar 'chr lst)))
  2. (defun str->lst (str / n lst)
  3.   (setq n (1+ (strlen str)))
  4.   (while (> (setq n (1- n)) 0) (setq lst (cons (ascii (substr str n 1)) lst)))
  5.   lst)
But when I use these I loose the 0. It seems that the strcat / chr functions simply does not work with "\000" - it becomes an empty string.
« Last Edit: May 25, 2012, 06:18:28 AM by irneb »
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Create a binary file from scratch!
« Reply #12 on: May 25, 2012, 06:23:55 AM »
OK So here's my versions making use of my own rolled str->lst & lst->str. Added Keith's suggestion of using 256 as the value for 0:
Code - Auto/Visual Lisp: [Select]
  1.  
  2. (defun lst->str (lst /) (apply 'strcat (mapcar '(lambda (n) (chr (cond ((< 0 n 256) n) (t 256)))) lst)))
  3. (defun str->lst (str / n lst)
  4.   (setq n (1+ (strlen str)))
  5.   (while (> (setq n (1- n)) 0) (setq lst (cons (ascii (substr str n 1)) lst)))
  6.   lst)
  7.  
  8. (defun BinFile-Read  (FileName / fso stream file result)
  9.   (if (setq FileName (findfile FileName))
  10.     (vl-catch-all-apply
  11.       '(lambda (/ size)
  12.          (setq fso    (vlax-create-object "Scripting.FileSystemObject")
  13.                file   (vlax-invoke fso 'GetFile FileName)
  14.                stream (vlax-invoke fso 'OpenTextFile FileName 1 :vlax-false 0)
  15.                size   (vlax-get file 'Size)
  16.                result (vlax-invoke stream 'read size))
  17.          (vlax-invoke stream 'Close))))
  18.   (if stream
  19.     (vlax-release-object stream))
  20.   (if file
  21.     (vlax-release-object file))
  22.   (if fso
  23.     (vlax-release-object fso))
  24.   (if result
  25.     (str->lst result)))
  26.  
  27. (defun BinFile-Write  (FileName lst / fso stream file result)
  28.   (vl-catch-all-apply
  29.     '(lambda (/ size)
  30.        (setq fso    (vlax-create-object "Scripting.FileSystemObject")
  31.              stream (vlax-invoke fso 'OpenTextFile FileName 2 :vlax-true 0))
  32.        (vlax-invoke stream 'Write (lst->str lst))
  33.        (vlax-invoke stream 'Close)
  34.        (setq file   (vlax-invoke fso 'GetFile FileName)
  35.              result (vlax-get file 'Size))))
  36.   (if stream
  37.     (vlax-release-object stream))
  38.   (if file
  39.     (vlax-release-object file))
  40.   (if fso
  41.     (vlax-release-object fso))
  42.   result)
It now seems to work fine. Could you try in BC? If it's still not working then it must be the method BC uses to send strings to ActiveX objects, in which case your original seems to be the only way to do this in BC.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Create a binary file from scratch!
« Reply #13 on: May 25, 2012, 08:38:42 AM »
Using 256 to write a binary null is not supported in autolisp ... in the help file, it states in part
Quote
It is not possible to write a null character to file with lisp

Obviously using 256 does work in AutoCAD, so as has been suggested previously, I suspect it is a Briscad implementation issue.
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Create a binary file from scratch!
« Reply #14 on: May 25, 2012, 08:58:28 AM »
Here is another method using adodb

http://www.theswamp.org/index.php?topic=36656.0
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie