1    
2    /* ====================================================================
3     * The Apache Software License, Version 1.1
4     *
5     * Copyright (c) 2002 The Apache Software Foundation.  All rights
6     * reserved.
7     *
8     * Redistribution and use in source and binary forms, with or without
9     * modification, are permitted provided that the following conditions
10    * are met:
11    *
12    * 1. Redistributions of source code must retain the above copyright
13    *    notice, this list of conditions and the following disclaimer.
14    *
15    * 2. Redistributions in binary form must reproduce the above copyright
16    *    notice, this list of conditions and the following disclaimer in
17    *    the documentation and/or other materials provided with the
18    *    distribution.
19    *
20    * 3. The end-user documentation included with the redistribution,
21    *    if any, must include the following acknowledgment:
22    *       "This product includes software developed by the
23    *        Apache Software Foundation (http://www.apache.org/)."
24    *    Alternately, this acknowledgment may appear in the software itself,
25    *    if and wherever such third-party acknowledgments normally appear.
26    *
27    * 4. The names "Apache" and "Apache Software Foundation" and
28    *    "Apache POI" must not be used to endorse or promote products
29    *    derived from this software without prior written permission. For
30    *    written permission, please contact apache@apache.org.
31    *
32    * 5. Products derived from this software may not be called "Apache",
33    *    "Apache POI", nor may "Apache" appear in their name, without
34    *    prior written permission of the Apache Software Foundation.
35    *
36    * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37    * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38    * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39    * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40    * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41    * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42    * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43    * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44    * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46    * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47    * SUCH DAMAGE.
48    * ====================================================================
49    *
50    * This software consists of voluntary contributions made by many
51    * individuals on behalf of the Apache Software Foundation.  For more
52    * information on the Apache Software Foundation, please see
53    * <http://www.apache.org/>.
54    */
55   
56   package org.apache.poi.hssf.record;
57   
58   import org.apache.poi.util.HexDump;
59   import org.apache.poi.util.LittleEndian;
60   import org.apache.poi.util.StringUtil;
61   import java.util.Stack;
62   import org.apache.poi.hssf.record.formula.Ptg;
63   import org.apache.poi.hssf.record.formula.Area3DPtg;
64   import org.apache.poi.hssf.record.formula.Ref3DPtg;
65   import java.util.List;
66   import org.apache.poi.hssf.util.RangeAddress;
67   import org.apache.poi.hssf.util.SheetReferences;
68   
69   /**
70    * Title:        Name Record (aka Named Range) <P>
71    * Description:  Defines a named range within a workbook. <P>
72    * REFERENCE:  <P>
73    * @author Libin Roman (Vista Portal LDT. Developer)
74    * @author  Sergei Kozello (sergeikozello at mail.ru)
75    * @author Glen Stampoultzis (glens at apache.org)
76    * @version 1.0-pre
77    */
78   
79   public class NameRecord extends Record {
80       /**
81        */
82       public final static short sid = 0x18; //Docs says that it is 0x218
83       private short             field_1_option_flag;
84       private byte              field_2_keyboard_shortcut;
85       private byte              field_3_length_name_text;
86       private short             field_4_length_name_definition;
87       private short             field_5_index_to_sheet;     // unused: see field_6
88       private short             field_6_equals_to_index_to_sheet;
89       private byte              field_7_length_custom_menu;
90       private byte              field_8_length_description_text;
91       private byte              field_9_length_help_topic_text;
92       private byte              field_10_length_status_bar_text;
93       private byte              field_11_compressed_unicode_flag;   // not documented
94       private byte              field_12_builtIn_name;
95       private String            field_12_name_text;
96       private Stack             field_13_name_definition;
97       private byte[]            field_13_raw_name_definition;       // raw data
98       private String            field_14_custom_menu_text;
99       private String            field_15_description_text;
100      private String            field_16_help_topic_text;
101      private String            field_17_status_bar_text;
102  
103  
104      /** Creates new NameRecord */
105      public NameRecord() {
106          field_13_name_definition = new Stack();
107  
108          field_12_name_text = new String();
109          field_14_custom_menu_text = new String();
110          field_15_description_text = new String();
111          field_16_help_topic_text = new String();
112          field_17_status_bar_text = new String();
113      }
114  
115      /**
116       * Constructs a Name record and sets its fields appropriately.
117       *
118       * @param id     id must be 0x18 or an exception will be throw upon validation
119       * @param size  the size of the data area of the record
120       * @param data  data of the record (should not contain sid/len)
121       */
122      public NameRecord(short id, short size, byte [] data) {
123          super(id, size, data);
124      }
125  
126      /**
127       * Constructs a Name record and sets its fields appropriately.
128       *
129       * @param id     id must be 0x18 or an exception will be throw upon validation
130       * @param size  the size of the data area of the record
131       * @param data  data of the record (should not contain sid/len)
132       * @param offset of the record's data
133       */
134      public NameRecord(short id, short size, byte [] data, int offset) {
135          super(id, size, data, offset);
136      }
137  
138      /** sets the option flag for the named range
139       * @param flag option flag
140       */
141      public void setOptionFlag(short flag){
142          field_1_option_flag = flag;
143      }
144  
145      /** sets the keyboard shortcut
146       * @param shortcut keyboard shortcut
147       */
148      public void setKeyboardShortcut(byte shortcut){
149          field_2_keyboard_shortcut = shortcut;
150      }
151  
152      /** sets the name of the named range length
153       * @param length name length
154       */
155      public void setNameTextLength(byte length){
156          field_3_length_name_text = length;
157      }
158  
159      /** sets the definition (reference - formula) length
160       * @param length defenition length
161       */
162      public void setDefinitionTextLength(short length){
163          field_4_length_name_definition = length;
164      }
165  
166      /** sets the index number to the extern sheet (thats is what writen in documentation
167       *  but as i saw , it works differently)
168       * @param index extern sheet index
169       */
170      public void setUnused(short index){
171          field_5_index_to_sheet = index;
172  
173          // field_6_equals_to_index_to_sheet is equal to field_5_index_to_sheet
174  //        field_6_equals_to_index_to_sheet = index;
175      }
176  
177      public short getEqualsToIndexToSheet()
178      {
179          return field_6_equals_to_index_to_sheet;
180      }
181  
182      public void setEqualsToIndexToSheet(short value)
183      {
184          field_6_equals_to_index_to_sheet = value;
185      }
186  
187  
188      /** sets the custom menu length
189       * @param length custom menu length
190       */
191      public void setCustomMenuLength(byte length){
192          field_7_length_custom_menu = length;
193      }
194  
195      /** sets the length of named range description
196       * @param length description length
197       */
198      public void setDescriptionTextLength(byte length){
199          field_8_length_description_text = length;
200      }
201  
202      /** sets the help topic length
203       * @param length help topic length
204       */
205      public void setHelpTopicLength(byte length){
206          field_9_length_help_topic_text = length;
207      }
208  
209      /** sets the length of the status bar text
210       * @param length status bar text length
211       */
212      public void setStatusBarLength(byte length){
213          field_10_length_status_bar_text = length;
214      }
215  
216      /** sets the compressed unicode flag
217       * @param flag unicode flag
218       */
219      public void setCompressedUnicodeFlag(byte flag) {
220          field_11_compressed_unicode_flag = flag;
221      }
222  
223      /** sets the name of the named range
224       * @param name named range name
225       */
226      public void setNameText(String name){
227          field_12_name_text = name;
228      }
229  
230      //    public void setNameDefintion(String definition){
231      //        test = definition;
232      //    }
233  
234      /** sets the custom menu text
235       * @param text custom menu text
236       */
237      public void setCustomMenuText(String text){
238          field_14_custom_menu_text = text;
239      }
240  
241      /** sets the description text
242       * @param text the description text
243       */
244      public void setDescriptionText(String text){
245          field_15_description_text = text;
246      }
247  
248      /** sets the help topic text
249       * @param text help topix text
250       */
251      public void setHelpTopicText(String text){
252          field_16_help_topic_text = text;
253      }
254  
255      /** sets the status bar text
256       * @param text status bar text
257       */
258      public void setStatusBarText(String text){
259          field_17_status_bar_text = text;
260      }
261  
262      /** gets the option flag
263       * @return option flag
264       */
265      public short getOptionFlag(){
266          return field_1_option_flag;
267      }
268  
269      /** returns the keyboard shortcut
270       * @return keyboard shortcut
271       */
272      public byte getKeyboardShortcut(){
273          return field_2_keyboard_shortcut ;
274      }
275  
276      /** gets the name length
277       * @return name length
278       */
279      public byte getNameTextLength(){
280          return field_3_length_name_text;
281      }
282  
283      /** get the definition length
284       * @return definition length
285       */
286      public short getDefinitionTextLength(){
287          return field_4_length_name_definition;
288      }
289  
290      /** gets the index to extern sheet
291       * @return index to extern sheet
292       */
293      public short getUnused(){
294          return field_5_index_to_sheet;
295      }
296  
297      /** gets the custom menu length
298       * @return custom menu length
299       */
300      public byte getCustomMenuLength(){
301          return field_7_length_custom_menu;
302      }
303  
304      /** gets the description text length
305       * @return description text length
306       */
307      public byte getDescriptionTextLength(){
308          return field_8_length_description_text;
309      }
310  
311      /** gets the help topic length
312       * @return help topic length
313       */
314      public byte getHelpTopicLength(){
315          return field_9_length_help_topic_text;
316      }
317  
318      /** get the status bar text length
319       * @return satus bar length
320       */
321      public byte getStatusBarLength(){
322          return field_10_length_status_bar_text;
323      }
324  
325      /** gets the name compressed Unicode flag
326       * @return compressed unicode flag
327       */
328      public byte getCompressedUnicodeFlag() {
329          return field_11_compressed_unicode_flag;
330      }
331  
332      /** gets the name
333       * @return name
334       */
335      public String getNameText(){
336          return field_12_name_text;
337      }
338  
339      /** gets the definition, reference (Formula)
340       * @return definition -- can be null if we cant parse ptgs
341       */
342      public List getNameDefinition() {
343          return field_13_name_definition;
344      }
345  
346      public void setNameDefinition(Stack nameDefinition) {
347          field_13_name_definition = nameDefinition;
348      }
349  
350      /** get the custom menu text
351       * @return custom menu text
352       */
353      public String getCustomMenuText(){
354          return field_14_custom_menu_text;
355      }
356  
357      /** gets the description text
358       * @return description text
359       */
360      public String getDescriptionText(){
361          return field_15_description_text;
362      }
363  
364      /** get the help topic text
365       * @return gelp topic text
366       */
367      public String getHelpTopicText(){
368          return field_16_help_topic_text;
369      }
370  
371      /** gets the status bar text
372       * @return status bar text
373       */
374      public String getStatusBarText(){
375          return field_17_status_bar_text;
376      }
377  
378      /**
379       * called by constructor, should throw runtime exception in the event of a
380       * record passed with a differing ID.
381       *
382       * @param id alleged id for this record
383       */
384      protected void validateSid(short id) {
385          if (id != sid) {
386              throw new RecordFormatException("NOT A valid Name RECORD");
387          }
388      }
389  
390      /**
391       * called by the class that is responsible for writing this sucker.
392       * Subclasses should implement this so that their data is passed back in a
393       * byte array.
394       *
395       * @param offset to begin writing at
396       * @param data byte array containing instance data
397       * @return number of bytes written
398       */
399      public int serialize( int offset, byte[] data )
400      {
401          LittleEndian.putShort( data, 0 + offset, sid );
402          // size defined below
403          LittleEndian.putShort( data, 4 + offset, getOptionFlag() );
404          data[6 + offset] = getKeyboardShortcut();
405          data[7 + offset] = getNameTextLength();
406          LittleEndian.putShort( data, 8 + offset, getDefinitionTextLength() );
407          LittleEndian.putShort( data, 10 + offset, getUnused() );
408          LittleEndian.putShort( data, 12 + offset, getEqualsToIndexToSheet() );
409          data[14 + offset] = getCustomMenuLength();
410          data[15 + offset] = getDescriptionTextLength();
411          data[16 + offset] = getHelpTopicLength();
412          data[17 + offset] = getStatusBarLength();
413          data[18 + offset] = getCompressedUnicodeFlag();
414  
415          /* temp: gjs
416          if ( ( field_1_option_flag & (short) 0x20 ) != 0 )
417          {
418              LittleEndian.putShort( data, 2 + offset, (short) ( 16 + field_13_raw_name_definition.length ) );
419  
420              data[19 + offset] = field_12_builtIn_name;
421              System.arraycopy( field_13_raw_name_definition, 0, data, 20 + offset, field_13_raw_name_definition.length );
422  
423              return 20 + field_13_raw_name_definition.length;
424          }
425          else
426          {     */
427              LittleEndian.putShort( data, 2 + offset, (short) ( 15 + getTextsLength() ) );
428  
429  
430              StringUtil.putCompressedUnicode( getNameText(), data, 19 + offset );
431  
432              int start_of_name_definition = 19 + field_3_length_name_text;
433              if ( this.field_13_name_definition != null )
434              {
435                  serializePtgs( data, start_of_name_definition + offset );
436              }
437              else
438              {
439                  System.arraycopy( field_13_raw_name_definition, 0, data
440                          , start_of_name_definition + offset, field_13_raw_name_definition.length );
441              }
442  
443              int start_of_custom_menu_text = start_of_name_definition + field_4_length_name_definition;
444              StringUtil.putCompressedUnicode( getCustomMenuText(), data, start_of_custom_menu_text + offset );
445  
446              int start_of_description_text = start_of_custom_menu_text + field_8_length_description_text;
447              StringUtil.putCompressedUnicode( getDescriptionText(), data, start_of_description_text + offset );
448  
449              int start_of_help_topic_text = start_of_description_text + field_9_length_help_topic_text;
450              StringUtil.putCompressedUnicode( getHelpTopicText(), data, start_of_help_topic_text + offset );
451  
452              int start_of_status_bar_text = start_of_help_topic_text + field_10_length_status_bar_text;
453              StringUtil.putCompressedUnicode( getStatusBarText(), data, start_of_status_bar_text + offset );
454  
455              return getRecordSize();
456          /* } */
457      }
458  
459      private void serializePtgs(byte [] data, int offset) {
460          int pos = offset;
461  
462          for (int k = 0; k < field_13_name_definition.size(); k++) {
463              Ptg ptg = ( Ptg ) field_13_name_definition.get(k);
464  
465              ptg.writeBytes(data, pos);
466              pos += ptg.getSize();
467          }
468      }
469  
470  
471      /** gets the length of all texts
472       * @return total length
473       */
474      public int getTextsLength(){
475          int result;
476  
477          result = getNameTextLength() + getDefinitionTextLength() + getDescriptionTextLength() +
478          getHelpTopicLength() + getStatusBarLength();
479  
480  
481          return result;
482      }
483  
484      /** returns the record size
485       */
486      public int getRecordSize(){
487          int result;
488  
489          result = 19 + getTextsLength();
490  
491          return result;
492      }
493  
494      /** gets the extern sheet number
495       * @return extern sheet index
496       */
497      public short getExternSheetNumber(){
498          if (field_13_name_definition == null) return 0;
499          Ptg ptg = (Ptg) field_13_name_definition.peek();
500          short result = 0;
501  
502          if (ptg.getClass() == Area3DPtg.class){
503              result = ((Area3DPtg) ptg).getExternSheetIndex();
504  
505          } else if (ptg.getClass() == Ref3DPtg.class){
506              result = ((Ref3DPtg) ptg).getExternSheetIndex();
507          }
508  
509          return result;
510      }
511  
512      /** sets the extern sheet number
513       * @param externSheetNumber extern sheet number
514       */
515      public void setExternSheetNumber(short externSheetNumber){
516          Ptg ptg;
517  
518          if (field_13_name_definition == null || field_13_name_definition.isEmpty()){
519              field_13_name_definition = new Stack();
520              ptg = createNewPtg();
521          } else {
522              ptg = (Ptg) field_13_name_definition.peek();
523          }
524  
525          if (ptg.getClass() == Area3DPtg.class){
526              ((Area3DPtg) ptg).setExternSheetIndex(externSheetNumber);
527  
528          } else if (ptg.getClass() == Ref3DPtg.class){
529              ((Ref3DPtg) ptg).setExternSheetIndex(externSheetNumber);
530          }
531  
532      }
533  
534      private Ptg createNewPtg(){
535          Ptg ptg = new Area3DPtg();
536          field_13_name_definition.push(ptg);
537  
538          return ptg;
539      }
540  
541      /** gets the reference , the area only (range)
542       * @return area reference
543       */
544      public String getAreaReference(SheetReferences refs){
545          if (field_13_name_definition == null) return "#REF!";
546          Ptg ptg = (Ptg) field_13_name_definition.peek();
547          String result = "";
548  
549          if (ptg.getClass() == Area3DPtg.class){
550              result = ptg.toFormulaString(refs);
551  
552          } else if (ptg.getClass() == Ref3DPtg.class){
553              result = ptg.toFormulaString(refs);
554          }
555  
556          return result;
557      }
558  
559      /** sets the reference , the area only (range)
560       * @param ref area reference
561       */
562      public void setAreaReference(String ref){
563          //Trying to find if what ptg do we need
564          RangeAddress ra = new RangeAddress(ref);
565          Ptg oldPtg;
566          Ptg ptg;
567  
568          if (field_13_name_definition==null ||field_13_name_definition.isEmpty()){
569              field_13_name_definition = new Stack();
570              oldPtg = createNewPtg();
571          } else {
572              //Trying to find extern sheet index
573              oldPtg = (Ptg) field_13_name_definition.pop();
574          }
575  
576          short externSheetIndex = 0;
577  
578          if (oldPtg.getClass() == Area3DPtg.class){
579              externSheetIndex =  ((Area3DPtg) oldPtg).getExternSheetIndex();
580  
581          } else if (oldPtg.getClass() == Ref3DPtg.class){
582              externSheetIndex =  ((Ref3DPtg) oldPtg).getExternSheetIndex();
583          }
584  
585          if (ra.hasRange()) {
586              ptg = new Area3DPtg();
587              ((Area3DPtg) ptg).setExternSheetIndex(externSheetIndex);
588              ((Area3DPtg) ptg).setArea(ref);
589              this.setDefinitionTextLength((short)ptg.getSize());
590          } else {
591              ptg = new Ref3DPtg();
592              ((Ref3DPtg) ptg).setExternSheetIndex(externSheetIndex);
593              ((Ref3DPtg) ptg).setArea(ref);
594              this.setDefinitionTextLength((short)ptg.getSize());
595          }
596  
597          field_13_name_definition.push(ptg);
598  
599      }
600  
601      /**
602       * called by the constructor, should set class level fields.  Should throw
603       * runtime exception for bad/icomplete data.
604       *
605       * @param data raw data
606       * @param size size of data
607       * @param offset of the record's data (provided a big array of the file)
608       */
609      protected void fillFields(byte[] data, short size, int offset) {
610          field_1_option_flag             = LittleEndian.getShort(data, 0 + offset);
611          field_2_keyboard_shortcut       = data [2 + offset];
612          field_3_length_name_text        = data [3 + offset];
613          field_4_length_name_definition  = LittleEndian.getShort(data, 4 + offset);
614          field_5_index_to_sheet          = LittleEndian.getShort(data, 6 + offset);
615          field_6_equals_to_index_to_sheet= LittleEndian.getShort(data, 8 + offset);
616          field_7_length_custom_menu      = data [10 + offset];
617          field_8_length_description_text = data [11 + offset];
618          field_9_length_help_topic_text  = data [12 + offset];
619          field_10_length_status_bar_text = data [13 + offset];
620  
621  
622          /*
623          temp: gjs
624          if ( ( field_1_option_flag & (short)0x20 ) != 0 ) {
625              // DEBUG
626              // System.out.println( "Built-in name" );
627  
628              field_11_compressed_unicode_flag = data[ 14 + offset ];
629              field_12_builtIn_name = data[ 15 + offset ];
630  
631              if ( (field_12_builtIn_name & (short)0x07) != 0 ) {
632                  field_12_name_text = "Print_Titles";
633  
634                  // DEBUG
635                  // System.out.println( field_12_name_text );
636  
637                  field_13_raw_name_definition = new byte[ field_4_length_name_definition ];
638                  System.arraycopy( data, 16 + offset, field_13_raw_name_definition, 0, field_13_raw_name_definition.length );
639  
640                  // DEBUG
641                  // System.out.println( HexDump.toHex( field_13_raw_name_definition ) );
642              }
643          }
644          else { */
645      
646              field_11_compressed_unicode_flag= data [14 + offset];
647              field_12_name_text = new String(data, 15 + offset,
648              LittleEndian.ubyteToInt(field_3_length_name_text));
649          
650              int start_of_name_definition    = 15 + field_3_length_name_text;
651              field_13_name_definition = getParsedExpressionTokens(data, field_4_length_name_definition,
652              offset, start_of_name_definition);
653      
654              int start_of_custom_menu_text   = start_of_name_definition + field_4_length_name_definition;
655              field_14_custom_menu_text       = new String(data, start_of_custom_menu_text + offset,
656              LittleEndian.ubyteToInt(field_7_length_custom_menu));
657      
658              int start_of_description_text   = start_of_custom_menu_text + field_8_length_description_text;
659              field_15_description_text       = new String(data, start_of_description_text + offset,
660              LittleEndian.ubyteToInt(field_8_length_description_text));
661      
662              int start_of_help_topic_text    = start_of_description_text + field_9_length_help_topic_text;
663              field_16_help_topic_text        = new String(data, start_of_help_topic_text + offset,
664              LittleEndian.ubyteToInt(field_9_length_help_topic_text));
665      
666              int start_of_status_bar_text       = start_of_help_topic_text + field_10_length_status_bar_text;
667              field_17_status_bar_text        = new String(data, start_of_status_bar_text +  offset,
668              LittleEndian.ubyteToInt(field_10_length_status_bar_text));
669          /*} */
670      }
671  
672      private Stack getParsedExpressionTokens(byte [] data, short size,
673          int offset, int start_of_expression) {
674          Stack stack = new Stack();
675          int   pos           = start_of_expression + offset;
676          int   sizeCounter   = 0;
677          try {
678              while (sizeCounter < size) {
679                  Ptg ptg = Ptg.createPtg(data, pos);
680  
681                  pos += ptg.getSize();
682                  sizeCounter += ptg.getSize();
683                  stack.push(ptg);
684              }
685          } catch (java.lang.UnsupportedOperationException uoe) {
686              System.err.println("[WARNING] Unknown Ptg "
687                      + uoe.getMessage() );
688              field_13_raw_name_definition=new byte[size];
689              System.arraycopy(data,offset,field_13_raw_name_definition,0,size);
690              return null;
691          }
692          return stack;
693      }
694  
695  
696      /**
697       * return the non static version of the id for this record.
698       */
699      public short getSid() {
700          return this.sid;
701      }
702      /*
703        20 00 
704        00 
705        01 
706        1A 00 // sz = 0x1A = 26
707        00 00 
708        01 00 
709        00 
710        00 
711        00 
712        00 
713        00 // unicode flag
714        07 // name
715        
716        29 17 00 3B 00 00 00 00 FF FF 00 00 02 00 3B 00 //{ 26
717        00 07 00 07 00 00 00 FF 00 10                   //  }
718        
719        
720        
721        20 00 
722        00 
723        01 
724        0B 00 // sz = 0xB = 11
725        00 00 
726        01 00 
727        00 
728        00 
729        00 
730        00 
731        00 // unicode flag
732        07 // name
733        
734        3B 00 00 07 00 07 00 00 00 FF 00   // { 11 }
735    */
736      /*
737        18, 00, 
738        1B, 00, 
739        
740        20, 00, 
741        00, 
742        01, 
743        0B, 00, 
744        00, 
745        00, 
746        00, 
747        00, 
748        00, 
749        07, 
750        3B 00 00 07 00 07 00 00 00 FF 00 ]     
751       */
752  
753      /**
754       * @see Object#toString()
755       */
756      public String toString() {
757          StringBuffer buffer = new StringBuffer();
758  
759          buffer.append("[NAME]\n");
760          buffer.append("    .option flags         = ").append( HexDump.toHex( field_1_option_flag ) )
761              .append("\n");
762          buffer.append("    .keyboard shortcut    = ").append( HexDump.toHex( field_2_keyboard_shortcut ) )
763              .append("\n");
764          buffer.append("    .length of the name   = ").append( field_3_length_name_text )
765              .append("\n");
766          buffer.append("    .size of the formula data = ").append( field_4_length_name_definition )
767              .append("\n");
768          buffer.append("    .unused                   = ").append( field_5_index_to_sheet )
769              .append("\n");
770          buffer.append("    .( 0 = Global name, otherwise index to sheet (one-based) ) = ").append( field_6_equals_to_index_to_sheet )
771              .append("\n");
772          buffer.append("    .Length of menu text (character count)        = ").append( field_7_length_custom_menu )
773              .append("\n");
774          buffer.append("    .Length of description text (character count) = ").append( field_8_length_description_text )
775              .append("\n");
776          buffer.append("    .Length of help topic text (character count)  = ").append( field_9_length_help_topic_text )
777              .append("\n");
778          buffer.append("    .Length of status bar text (character count)  = ").append( field_10_length_status_bar_text )
779              .append("\n");
780          buffer.append("    .Name (Unicode flag)  = ").append( field_11_compressed_unicode_flag )
781              .append("\n");
782          buffer.append("    .Name (Unicode text)  = ").append( field_12_name_text )
783              .append("\n");
784          buffer.append("    .Formula data (RPN token array without size field)      = ").append( HexDump.toHex( 
785                         ((field_13_raw_name_definition != null) ? field_13_raw_name_definition : new byte[0] ) ) )
786              .append("\n");
787          buffer.append("    .Menu text (Unicode string without length field)        = ").append( field_14_custom_menu_text )
788              .append("\n");
789          buffer.append("    .Description text (Unicode string without length field) = ").append( field_15_description_text )
790              .append("\n");
791          buffer.append("    .Help topic text (Unicode string without length field)  = ").append( field_16_help_topic_text )
792              .append("\n");
793          buffer.append("    .Status bar text (Unicode string without length field)  = ").append( field_17_status_bar_text )
794              .append("\n");
795          buffer.append("[/NAME]\n");
796          
797          return buffer.toString();
798      }
799  
800  }
801