KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > alfresco > filesys > smb > mailslot > SMBMailslotPacket


1 /*
2  * Copyright (C) 2005 Alfresco, Inc.
3  *
4  * Licensed under the Mozilla Public License version 1.1
5  * with a permitted attribution clause. You may obtain a
6  * copy of the License at
7  *
8  * http://www.alfresco.org/legal/license.txt
9  *
10  * Unless required by applicable law or agreed to in writing,
11  * software distributed under the License is distributed on an
12  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific
14  * language governing permissions and limitations under the
15  * License.
16  */

17 package org.alfresco.filesys.smb.mailslot;
18
19 import org.alfresco.filesys.util.DataPacker;
20
21 /**
22  * SMB Mailslot Packet Class
23  */

24 public class SMBMailslotPacket
25 {
26     // SMB packet offsets
27

28     public static final int SIGNATURE = 0;
29     public static final int COMMAND = 4;
30     public static final int ERRORCODE = 5;
31     public static final int ERRORCLASS = 5;
32     public static final int ERROR = 7;
33     public static final int FLAGS = 9;
34     public static final int FLAGS2 = 10;
35     public static final int PIDHIGH = 12;
36     public static final int SID = 18;
37     public static final int SEQNO = 20;
38     public static final int TID = 24;
39     public static final int PID = 26;
40     public static final int UID = 28;
41     public static final int MID = 30;
42     public static final int WORDCNT = 32;
43     public static final int ANDXCOMMAND = 33;
44     public static final int ANDXRESERVED= 34;
45     public static final int PARAMWORDS = 33;
46
47     // SMB packet header length for a transaction type request
48

49     public static final int TRANS_HEADERLEN = 66;
50
51     // Minimum receive length for a valid SMB packet
52

53     public static final int MIN_RXLEN = 32;
54
55     // Default buffer size to allocate for SMB mailslot packets
56

57     public static final int DEFAULT_BUFSIZE = 500;
58
59     // Flag bits
60

61     public static final int FLG_SUBDIALECT = 0x01;
62     public static final int FLG_CASELESS = 0x08;
63     public static final int FLG_CANONICAL = 0x10;
64     public static final int FLG_OPLOCK = 0x20;
65     public static final int FLG_NOTIFY = 0x40;
66     public static final int FLG_RESPONSE = 0x80;
67
68     // Flag2 bits
69

70     public static final int FLG2_LONGFILENAMES = 0x0001;
71     public static final int FLG2_EXTENDEDATTRIB = 0x0002;
72     public static final int FLG2_READIFEXE = 0x2000;
73     public static final int FLG2_LONGERRORCODE = 0x4000;
74     public static final int FLG2_UNICODE = 0x8000;
75
76     // SMB packet buffer and offset
77

78     private byte[] m_smbbuf;
79     private int m_offset;
80
81     // Define the number of standard parameters for a server response
82

83     private static final int STD_PARAMS = 14;
84
85     // SMB packet types we expect to receive in a mailslot
86

87     public static final int Transaction = 0x25;
88     public static final int Transaction2 = 0x32;
89
90     /**
91      * Default constructor
92      */

93     public SMBMailslotPacket()
94     {
95         m_smbbuf = new byte[DEFAULT_BUFSIZE];
96         m_offset = 0;
97     }
98
99     /**
100      * Class constructor
101      *
102      * @param buf byte[]
103      */

104     public SMBMailslotPacket(byte[] buf)
105     {
106         m_smbbuf = buf;
107         m_offset = 0;
108     }
109
110     /**
111      * Class constructor
112      *
113      * @param buf byte[]
114      * @param off int
115      */

116     public SMBMailslotPacket(byte[] buf, int off)
117     {
118         m_smbbuf = buf;
119         m_offset = off;
120     }
121
122     /**
123      * Reset the mailslot packet to use the specified buffer and offset
124      *
125      * @param buf byte[]
126      * @param offset int
127      */

128     public final void resetPacket(byte[] buf, int offset)
129     {
130         m_smbbuf = buf;
131         m_offset = offset;
132     }
133
134     /**
135      * Get the secondary command code
136      *
137      * @return Secondary command code
138      */

139     public final int getAndXCommand()
140     {
141         return (int) (m_smbbuf[ANDXCOMMAND + m_offset] & 0xFF);
142     }
143
144     /**
145      * Return the byte array used for the SMB packet
146      *
147      * @return Byte array used for the SMB packet.
148      */

149     public final byte[] getBuffer()
150     {
151         return m_smbbuf;
152     }
153
154     /**
155      * Return the total buffer size available to the SMB request
156      *
157      * @return Total SMB buffer length available.
158      */

159     public final int getBufferLength()
160     {
161         return m_smbbuf.length - m_offset;
162     }
163
164     /**
165      * Get the data byte count for the SMB packet
166      *
167      * @return Data byte count
168      */

169     public final int getByteCount()
170     {
171
172         // Calculate the offset of the byte count
173

174         int pos = PARAMWORDS + (2 * getParameterCount());
175         return (int) DataPacker.getIntelShort(m_smbbuf, pos);
176     }
177
178     /**
179      * Get the data byte area offset within the SMB packet
180      *
181      * @return Data byte offset within the SMB packet.
182      */

183     public final int getByteOffset()
184     {
185
186         // Calculate the offset of the byte buffer
187

188         int pCnt = getParameterCount();
189         int pos = WORDCNT + (2 * pCnt) + 3 + m_offset;
190         return pos;
191     }
192
193     /**
194      * Get the SMB command
195      *
196      * @return SMB command code.
197      */

198     public final int getCommand()
199     {
200         return (int) (m_smbbuf[COMMAND + m_offset] & 0xFF);
201     }
202
203     /**
204      * Determine if normal or long error codes have been returned
205      *
206      * @return boolean
207      */

208     public final boolean hasLongErrorCode()
209     {
210         if ((getFlags2() & FLG2_LONGERRORCODE) == 0)
211             return false;
212         return true;
213     }
214
215     /**
216      * Get the SMB error class
217      *
218      * @return SMB error class.
219      */

220     public final int getErrorClass()
221     {
222         return (int) m_smbbuf[ERRORCLASS + m_offset] & 0xFF;
223     }
224
225     /**
226      * Get the SMB error code
227      *
228      * @return SMB error code.
229      */

230     public final int getErrorCode()
231     {
232         return (int) m_smbbuf[ERROR + m_offset] & 0xFF;
233     }
234
235     /**
236      * Get the SMB flags value.
237      *
238      * @return SMB flags value.
239      */

240     public final int getFlags()
241     {
242         return (int) m_smbbuf[FLAGS + m_offset] & 0xFF;
243     }
244
245     /**
246      * Get the SMB flags2 value.
247      *
248      * @return SMB flags2 value.
249      */

250     public final int getFlags2()
251     {
252         return (int) DataPacker.getIntelShort(m_smbbuf, FLAGS2 + m_offset);
253     }
254
255     /**
256      * Calculate the total used packet length.
257      *
258      * @return Total used packet length.
259      */

260     public final int getLength()
261     {
262         return (getByteOffset() + getByteCount()) - m_offset;
263     }
264
265     /**
266      * Get the long SMB error code
267      *
268      * @return Long SMB error code.
269      */

270     public final int getLongErrorCode()
271     {
272         return DataPacker.getIntelInt(m_smbbuf, ERRORCODE + m_offset);
273     }
274
275     /**
276      * Get the multiplex identifier.
277      *
278      * @return Multiplex identifier.
279      */

280     public final int getMultiplexId()
281     {
282         return DataPacker.getIntelShort(m_smbbuf, MID + m_offset);
283     }
284
285     /**
286      * Get a parameter word from the SMB packet.
287      *
288      * @param idx Parameter index (zero based).
289      * @return Parameter word value.
290      * @exception java.lang.IndexOutOfBoundsException If the parameter index is out of range.
291      */

292     public final int getParameter(int idx) throws java.lang.IndexOutOfBoundsException JavaDoc
293     {
294
295         // Range check the parameter index
296

297         if (idx > getParameterCount())
298             throw new java.lang.IndexOutOfBoundsException JavaDoc();
299
300         // Calculate the parameter word offset
301

302         int pos = WORDCNT + (2 * idx) + 1 + m_offset;
303         return (int) (DataPacker.getIntelShort(m_smbbuf, pos) & 0xFFFF);
304     }
305
306     /**
307      * Get the parameter count
308      *
309      * @return Parameter word count.
310      */

311     public final int getParameterCount()
312     {
313         return (int) m_smbbuf[WORDCNT + m_offset];
314     }
315
316     /**
317      * Get the process indentifier (PID)
318      *
319      * @return Process identifier value.
320      */

321     public final int getProcessId()
322     {
323         return DataPacker.getIntelShort(m_smbbuf, PID + m_offset);
324     }
325
326     /**
327      * Get the tree identifier (TID)
328      *
329      * @return Tree identifier (TID)
330      */

331     public final int getTreeId()
332     {
333         return DataPacker.getIntelShort(m_smbbuf, TID + m_offset);
334     }
335
336     /**
337      * Get the user identifier (UID)
338      *
339      * @return User identifier (UID)
340      */

341     public final int getUserId()
342     {
343         return DataPacker.getIntelShort(m_smbbuf, UID + m_offset);
344     }
345
346     /**
347      * Return the offset to the data block within the SMB packet. The data block is word aligned
348      * within the byte buffer area of the SMB packet. This method must be called after the parameter
349      * count and parameter block length have been set.
350      *
351      * @return int Offset to the data block area.
352      */

353     public final int getDataBlockOffset()
354     {
355
356         // Get the position of the parameter block
357

358         int pos = (getParameterBlockOffset() + getParameter(3)) + m_offset;
359         if ((pos & 0x01) != 0)
360             pos++;
361         return pos;
362     }
363
364     /**
365      * Return the offset to the data block within the SMB packet. The data block is word aligned
366      * within the byte buffer area of the SMB packet. This method must be called after the parameter
367      * count has been set.
368      *
369      * @param prmLen Parameter block length, in bytes.
370      * @return int Offset to the data block area.
371      */

372     public final int getDataBlockOffset(int prmLen)
373     {
374
375         // Get the position of the parameter block
376

377         int pos = getParameterBlockOffset() + prmLen;
378         if ((pos & 0x01) != 0)
379             pos++;
380         return pos;
381     }
382
383     /**
384      * Return the parameter block offset where the parameter bytes should be placed. This method
385      * must be called after the paramter count has been set. The parameter offset is word aligned.
386      *
387      * @return int Offset to the parameter block area.
388      */

389     public final int getParameterBlockOffset()
390     {
391
392         // Get the offset to the byte buffer area of the SMB packet
393

394         int pos = getByteOffset() + m_offset;
395         if ((pos & 0x01) != 0)
396             pos++;
397         return pos;
398     }
399
400     /**
401      * Return the data block offset.
402      *
403      * @return int Offset to data block within packet.
404      */

405     public final int getRxDataBlock()
406     {
407         return getParameter(12) + m_offset;
408     }
409
410     /**
411      * Return the received transaction data block length.
412      *
413      * @return int
414      */

415     public final int getRxDataBlockLength()
416     {
417         return getParameter(11);
418     }
419
420     /**
421      * Get the required transact parameter word (16 bit).
422      *
423      * @param prmIdx int
424      * @return int
425      */

426     public final int getRxParameter(int prmIdx)
427     {
428
429         // Get the parameter block offset
430

431         int pos = getRxParameterBlock();
432
433         // Get the required transact parameter word.
434

435         pos += prmIdx * 2; // 16 bit words
436
return DataPacker.getIntelShort(getBuffer(), pos);
437     }
438
439     /**
440      * Return the position of the parameter block within the received packet.
441      *
442      * @param prmblk Array to unpack the parameter block words into.
443      */

444     public final int getRxParameterBlock()
445     {
446
447         // Get the offset to the parameter words
448

449         return getParameter(10) + m_offset;
450     }
451
452     /**
453      * Return the received transaction parameter block length.
454      *
455      * @return int
456      */

457     public final int getRxParameterBlockLength()
458     {
459         return getParameter(9);
460     }
461
462     /**
463      * Return the received transaction setup parameter count.
464      *
465      * @return int
466      */

467     public final int getRxParameterCount()
468     {
469         return getParameterCount() - STD_PARAMS;
470     }
471
472     /**
473      * Get the required transact parameter int value (32-bit).
474      *
475      * @param prmIdx int
476      * @return int
477      */

478     public final int getRxParameterInt(int prmIdx)
479     {
480
481         // Get the parameter block offset
482

483         int pos = getRxParameterBlock();
484
485         // Get the required transact parameter word.
486

487         pos += prmIdx * 2; // 16 bit words
488
return DataPacker.getIntelInt(getBuffer(), pos);
489     }
490
491     /**
492      * Get the required transact parameter string.
493      *
494      * @param pos Offset to the string within the parameter block.
495      * @return int
496      */

497     public final String JavaDoc getRxParameterString(int pos)
498     {
499
500         // Get the parameter block offset
501

502         pos += getRxParameterBlock();
503
504         // Get the transact parameter string
505

506         byte[] buf = getBuffer();
507         int len = (buf[pos++] & 0x00FF);
508         return DataPacker.getString(buf, pos, len);
509     }
510
511     /**
512      * Get the required transact parameter string.
513      *
514      * @param pos Offset to the string within the parameter block.
515      * @param len Length of the string.
516      * @return int
517      */

518     public final String JavaDoc getRxParameterString(int pos, int len)
519     {
520
521         // Get the parameter block offset
522

523         pos += getRxParameterBlock();
524
525         // Get the transact parameter string
526

527         byte[] buf = getBuffer();
528         return DataPacker.getString(buf, pos, len);
529     }
530
531     /**
532      * Return the received transaction name.
533      *
534      * @return java.lang.String
535      */

536     public final String JavaDoc getRxTransactName()
537     {
538
539         // Check if the transaction has a name
540

541         if (getCommand() == Transaction2)
542             return "";
543
544         // Unpack the transaction name string
545

546         int pos = getByteOffset();
547         return DataPacker.getString(getBuffer(), pos, getByteCount());
548     }
549
550     /**
551      * Return the specified transaction setup parameter.
552      *
553      * @param idx Setup parameter index.
554      */

555     public final int getSetupParameter(int idx) throws java.lang.ArrayIndexOutOfBoundsException JavaDoc
556     {
557
558         // Check if the setup parameter index is valid
559

560         if (idx >= getRxParameterCount())
561             throw new java.lang.ArrayIndexOutOfBoundsException JavaDoc();
562
563         // Get the setup parameter
564

565         return getParameter(idx + STD_PARAMS);
566     }
567
568     /**
569      * Return the mailslot opcode
570      *
571      * @return int
572      */

573     public final int getMailslotOpcode()
574     {
575         try
576         {
577             return getSetupParameter(0);
578         }
579         catch (ArrayIndexOutOfBoundsException JavaDoc ex)
580         {
581         }
582         return -1;
583     }
584
585     /**
586      * Return the mailslot priority
587      *
588      * @return int
589      */

590     public final int getMailslotPriority()
591     {
592         try
593         {
594             return getSetupParameter(1);
595         }
596         catch (ArrayIndexOutOfBoundsException JavaDoc ex)
597         {
598         }
599         return -1;
600     }
601
602     /**
603      * Return the mailslot class of service
604      *
605      * @return int
606      */

607     public final int getMailslotClass()
608     {
609         try
610         {
611             return getSetupParameter(2);
612         }
613         catch (ArrayIndexOutOfBoundsException JavaDoc ex)
614         {
615         }
616         return -1;
617     }
618
619     /**
620      * Return the mailslot sub-opcode, the first byte from the mailslot data
621      *
622      * @return int
623      */

624     public final int getMailslotSubOpcode()
625     {
626         return (int) (m_smbbuf[getMailslotDataOffset()] & 0xFF);
627     }
628
629     /**
630      * Return the mailslot data offset
631      *
632      * @return int
633      */

634     public final int getMailslotDataOffset()
635     {
636         return getRxDataBlock();
637     }
638
639     /**
640      * Initialize a mailslot SMB
641      *
642      * @param name Mailslot name
643      * @param data Request data bytes
644      * @param dlen Data length
645      */

646     public final void initializeMailslotSMB(String JavaDoc name, byte[] data, int dlen)
647     {
648
649         // Initialize the SMB packet header
650

651         initializeBuffer();
652
653         // Clear header values
654

655         setFlags(0);
656         setFlags2(0);
657         setUserId(0);
658         setMultiplexId(0);
659         setTreeId(0);
660         setProcessId(0);
661
662         // Initialize the transaction
663

664         initializeTransact(name, 17, null, 0, data, dlen);
665
666         // Initialize the transactin setup parameters for a mailslot write
667

668         setSetupParameter(0, MailSlot.WRITE);
669         setSetupParameter(1, 1);
670         setSetupParameter(2, MailSlot.UNRELIABLE);
671     }
672
673     /**
674      * Initialize the transact SMB packet
675      *
676      * @param name Transaction name
677      * @param pcnt Total parameter count for this transaction
678      * @param paramblk Parameter block data bytes
679      * @param plen Parameter block data length
680      * @param datablk Data block data bytes
681      * @param dlen Data block data length
682      */

683     protected final void initializeTransact(String JavaDoc name, int pcnt, byte[] paramblk, int plen, byte[] datablk, int dlen)
684     {
685
686         // Set the SMB command code
687

688         if (name == null)
689             setCommand(Transaction2);
690         else
691             setCommand(Transaction);
692
693         // Set the parameter count
694

695         setParameterCount(pcnt);
696
697         // Initialize the parameters
698

699         setParameter(0, plen); // total parameter bytes being sent
700
setParameter(1, dlen); // total data bytes being sent
701

702         for (int i = 2; i < 9; setParameter(i++, 0))
703             ;
704
705         setParameter(6, 1000); // timeout 1 second
706
setParameter(9, plen); // parameter bytes sent in this packet
707
setParameter(11, dlen); // data bytes sent in this packet
708

709         setParameter(13, pcnt - STD_PARAMS); // number of setup words
710

711         // Get the data byte offset
712

713         int pos = getByteOffset();
714         int startPos = pos;
715
716         // Check if this is a named transaction, if so then store the name
717

718         int idx;
719         byte[] buf = getBuffer();
720
721         if (name != null)
722         {
723
724             // Store the transaction name
725

726             byte[] nam = name.getBytes();
727
728             for (idx = 0; idx < nam.length; idx++)
729                 buf[pos++] = nam[idx];
730         }
731
732         // Word align the buffer offset
733

734         if ((pos % 2) > 0)
735             pos++;
736
737         // Store the parameter block
738

739         if (paramblk != null)
740         {
741
742             // Set the parameter block offset
743

744             setParameter(10, pos - m_offset);
745
746             // Store the parameter block
747

748             for (idx = 0; idx < plen; idx++)
749                 buf[pos++] = paramblk[idx];
750         }
751         else
752         {
753
754             // Clear the parameter block offset
755

756             setParameter(10, 0);
757         }
758
759         // Word align the data block
760

761         if ((pos % 2) > 0)
762             pos++;
763
764         // Store the data block
765

766         if (datablk != null)
767         {
768
769             // Set the data block offset
770

771             setParameter(12, pos - m_offset);
772
773             // Store the data block
774

775             for (idx = 0; idx < dlen; idx++)
776                 buf[pos++] = datablk[idx];
777         }
778         else
779         {
780
781             // Zero the data block offset
782

783             setParameter(12, 0);
784         }
785
786         // Set the byte count for the SMB packet
787

788         setByteCount(pos - startPos);
789     }
790
791     /**
792      * Set the secondary SMB command
793      *
794      * @param cmd Secondary SMB command code.
795      */

796     public final void setAndXCommand(int cmd)
797     {
798         m_smbbuf[ANDXCOMMAND + m_offset] = (byte) cmd;
799         m_smbbuf[ANDXRESERVED + m_offset] = (byte) 0;
800     }
801
802     /**
803      * Set the data byte count for this SMB packet
804      *
805      * @param cnt Data byte count.
806      */

807     public final void setByteCount(int cnt)
808     {
809         int offset = getByteOffset() - 2;
810         DataPacker.putIntelShort(cnt, m_smbbuf, offset);
811     }
812
813     /**
814      * Set the data byte area in the SMB packet
815      *
816      * @param byts Byte array containing the data to be copied to the SMB packet.
817      */

818     public final void setBytes(byte[] byts)
819     {
820         int offset = getByteOffset() - 2;
821         DataPacker.putIntelShort(byts.length, m_smbbuf, offset);
822
823         offset += 2;
824
825         for (int idx = 0; idx < byts.length; m_smbbuf[offset + idx] = byts[idx++])
826             ;
827     }
828
829     /**
830      * Set the SMB command
831      *
832      * @param cmd SMB command code
833      */

834     public final void setCommand(int cmd)
835     {
836         m_smbbuf[COMMAND + m_offset] = (byte) cmd;
837     }
838
839     /**
840      * Set the SMB error class.
841      *
842      * @param cl SMB error class.
843      */

844     public final void setErrorClass(int cl)
845     {
846         m_smbbuf[ERRORCLASS + m_offset] = (byte) (cl & 0xFF);
847     }
848
849     /**
850      * Set the SMB error code
851      *
852      * @param sts SMB error code.
853      */

854     public final void setErrorCode(int sts)
855     {
856         m_smbbuf[ERROR + m_offset] = (byte) (sts & 0xFF);
857     }
858
859     /**
860      * Set the SMB flags value.
861      *
862      * @param flg SMB flags value.
863      */

864     public final void setFlags(int flg)
865     {
866         m_smbbuf[FLAGS + m_offset] = (byte) flg;
867     }
868
869     /**
870      * Set the SMB flags2 value.
871      *
872      * @param flg SMB flags2 value.
873      */

874     public final void setFlags2(int flg)
875     {
876         DataPacker.putIntelShort(flg, m_smbbuf, FLAGS2 + m_offset);
877     }
878
879     /**
880      * Set the multiplex identifier.
881      *
882      * @param mid Multiplex identifier
883      */

884     public final void setMultiplexId(int mid)
885     {
886         DataPacker.putIntelShort(mid, m_smbbuf, MID + m_offset);
887     }
888
889     /**
890      * Set the specified parameter word.
891      *
892      * @param idx Parameter index (zero based).
893      * @param val Parameter value.
894      */

895     public final void setParameter(int idx, int val)
896     {
897         int pos = WORDCNT + (2 * idx) + 1 + m_offset;
898         DataPacker.putIntelShort(val, m_smbbuf, pos);
899     }
900
901     /**
902      * Set the parameter count
903      *
904      * @param cnt Parameter word count.
905      */

906     public final void setParameterCount(int cnt)
907     {
908         m_smbbuf[WORDCNT + m_offset] = (byte) cnt;
909     }
910
911     /**
912      * Set the process identifier value (PID).
913      *
914      * @param pid Process identifier value.
915      */

916     public final void setProcessId(int pid)
917     {
918         DataPacker.putIntelShort(pid, m_smbbuf, PID + m_offset);
919     }
920
921     /**
922      * Set the packet sequence number, for connectionless commands.
923      *
924      * @param seq Sequence number.
925      */

926     public final void setSeqNo(int seq)
927     {
928         DataPacker.putIntelShort(seq, m_smbbuf, SEQNO + m_offset);
929     }
930
931     /**
932      * Set the session id.
933      *
934      * @param sid Session id.
935      */

936     public final void setSID(int sid)
937     {
938         DataPacker.putIntelShort(sid, m_smbbuf, SID + m_offset);
939     }
940
941     /**
942      * Set the tree identifier (TID)
943      *
944      * @param tid Tree identifier value.
945      */

946     public final void setTreeId(int tid)
947     {
948         DataPacker.putIntelShort(tid, m_smbbuf, TID + m_offset);
949     }
950
951     /**
952      * Set the user identifier (UID)
953      *
954      * @param uid User identifier value.
955      */

956     public final void setUserId(int uid)
957     {
958         DataPacker.putIntelShort(uid, m_smbbuf, UID + m_offset);
959     }
960
961     /**
962      * Set the specifiec setup parameter within the SMB packet.
963      *
964      * @param idx Setup parameter index.
965      * @param val Setup parameter value.
966      */

967     public final void setSetupParameter(int idx, int val)
968     {
969         setParameter(STD_PARAMS + idx, val);
970     }
971
972     /**
973      * Initialize the SMB packet buffer.
974      */

975     private final void initializeBuffer()
976     {
977
978         // Set the packet signature
979

980         m_smbbuf[SIGNATURE + m_offset] = (byte) 0xFF;
981         m_smbbuf[SIGNATURE + 1 + m_offset] = (byte) 'S';
982         m_smbbuf[SIGNATURE + 2 + m_offset] = (byte) 'M';
983         m_smbbuf[SIGNATURE + 3 + m_offset] = (byte) 'B';
984     }
985 }
Popular Tags